tint/ast: Migrate to utils::Vector

Change-Id: I10dd2feeaeb86a1ee7769d2bfd172e49c2805cb3
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/97843
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
Ben Clayton 2022-08-02 17:03:35 +00:00 committed by Dawn LUCI CQ
parent 34d46731bb
commit 783b169bf4
277 changed files with 6823 additions and 5056 deletions

View File

@ -1110,6 +1110,7 @@ if (tint_build_unittests) {
"resolver/function_validation_test.cc", "resolver/function_validation_test.cc",
"resolver/host_shareable_validation_test.cc", "resolver/host_shareable_validation_test.cc",
"resolver/increment_decrement_validation_test.cc", "resolver/increment_decrement_validation_test.cc",
"resolver/inferred_type_test.cc",
"resolver/intrinsic_table_test.cc", "resolver/intrinsic_table_test.cc",
"resolver/is_host_shareable_test.cc", "resolver/is_host_shareable_test.cc",
"resolver/is_storeable_test.cc", "resolver/is_storeable_test.cc",

View File

@ -15,6 +15,7 @@
#include "src/tint/ast/array.h" #include "src/tint/ast/array.h"
#include <cmath> #include <cmath>
#include <utility>
#include "src/tint/program_builder.h" #include "src/tint/program_builder.h"
@ -42,8 +43,8 @@ Array::Array(ProgramID pid,
const Source& src, const Source& src,
const Type* subtype, const Type* subtype,
const Expression* cnt, const Expression* cnt,
AttributeList attrs) utils::VectorRef<const Attribute*> attrs)
: Base(pid, nid, src), type(subtype), count(cnt), attributes(attrs) {} : Base(pid, nid, src), type(subtype), count(cnt), attributes(std::move(attrs)) {}
Array::Array(Array&&) = default; Array::Array(Array&&) = default;
@ -73,7 +74,7 @@ const Array* Array::Clone(CloneContext* ctx) const {
auto* ty = ctx->Clone(type); auto* ty = ctx->Clone(type);
auto* cnt = ctx->Clone(count); auto* cnt = ctx->Clone(count);
auto attrs = ctx->Clone(attributes); auto attrs = ctx->Clone(attributes);
return ctx->dst->create<Array>(src, ty, cnt, attrs); return ctx->dst->create<Array>(src, ty, cnt, std::move(attrs));
} }
} // namespace tint::ast } // namespace tint::ast

View File

@ -43,7 +43,7 @@ class Array final : public Castable<Array, Type> {
const Source& src, const Source& src,
const Type* subtype, const Type* subtype,
const Expression* count, const Expression* count,
AttributeList attributes); utils::VectorRef<const Attribute*> attributes);
/// Move constructor /// Move constructor
Array(Array&&); Array(Array&&);
~Array() override; ~Array() override;
@ -69,7 +69,7 @@ class Array final : public Castable<Array, Type> {
const Expression* const count; const Expression* const count;
/// the array attributes /// the array attributes
const AttributeList attributes; const utils::Vector<const Attribute*, 1> attributes;
}; };
} // namespace tint::ast } // namespace tint::ast

View File

@ -26,7 +26,7 @@ using AstArrayTest = TestHelper;
TEST_F(AstArrayTest, CreateSizedArray) { TEST_F(AstArrayTest, CreateSizedArray) {
auto* u32 = create<U32>(); auto* u32 = create<U32>();
auto* count = Expr(3_u); auto* count = Expr(3_u);
auto* arr = create<Array>(u32, count, AttributeList{}); auto* arr = create<Array>(u32, count, utils::Empty);
EXPECT_EQ(arr->type, u32); EXPECT_EQ(arr->type, u32);
EXPECT_EQ(arr->count, count); EXPECT_EQ(arr->count, count);
EXPECT_TRUE(arr->Is<Array>()); EXPECT_TRUE(arr->Is<Array>());
@ -35,7 +35,7 @@ TEST_F(AstArrayTest, CreateSizedArray) {
TEST_F(AstArrayTest, CreateRuntimeArray) { TEST_F(AstArrayTest, CreateRuntimeArray) {
auto* u32 = create<U32>(); auto* u32 = create<U32>();
auto* arr = create<Array>(u32, nullptr, AttributeList{}); auto* arr = create<Array>(u32, nullptr, utils::Empty);
EXPECT_EQ(arr->type, u32); EXPECT_EQ(arr->type, u32);
EXPECT_EQ(arr->count, nullptr); EXPECT_EQ(arr->count, nullptr);
EXPECT_TRUE(arr->Is<Array>()); EXPECT_TRUE(arr->Is<Array>());
@ -43,7 +43,7 @@ TEST_F(AstArrayTest, CreateRuntimeArray) {
} }
TEST_F(AstArrayTest, CreateInferredTypeArray) { TEST_F(AstArrayTest, CreateInferredTypeArray) {
auto* arr = create<Array>(nullptr, nullptr, AttributeList{}); auto* arr = create<Array>(nullptr, nullptr, utils::Empty);
EXPECT_EQ(arr->type, nullptr); EXPECT_EQ(arr->type, nullptr);
EXPECT_EQ(arr->count, nullptr); EXPECT_EQ(arr->count, nullptr);
EXPECT_TRUE(arr->Is<Array>()); EXPECT_TRUE(arr->Is<Array>());
@ -52,35 +52,35 @@ TEST_F(AstArrayTest, CreateInferredTypeArray) {
TEST_F(AstArrayTest, FriendlyName_RuntimeSized) { TEST_F(AstArrayTest, FriendlyName_RuntimeSized) {
auto* i32 = create<I32>(); auto* i32 = create<I32>();
auto* arr = create<Array>(i32, nullptr, AttributeList{}); auto* arr = create<Array>(i32, nullptr, utils::Empty);
EXPECT_EQ(arr->FriendlyName(Symbols()), "array<i32>"); EXPECT_EQ(arr->FriendlyName(Symbols()), "array<i32>");
} }
TEST_F(AstArrayTest, FriendlyName_LiteralSized) { TEST_F(AstArrayTest, FriendlyName_LiteralSized) {
auto* i32 = create<I32>(); auto* i32 = create<I32>();
auto* arr = create<Array>(i32, Expr(5_u), AttributeList{}); auto* arr = create<Array>(i32, Expr(5_u), utils::Empty);
EXPECT_EQ(arr->FriendlyName(Symbols()), "array<i32, 5>"); EXPECT_EQ(arr->FriendlyName(Symbols()), "array<i32, 5>");
} }
TEST_F(AstArrayTest, FriendlyName_ConstantSized) { TEST_F(AstArrayTest, FriendlyName_ConstantSized) {
auto* i32 = create<I32>(); auto* i32 = create<I32>();
auto* arr = create<Array>(i32, Expr("size"), AttributeList{}); auto* arr = create<Array>(i32, Expr("size"), utils::Empty);
EXPECT_EQ(arr->FriendlyName(Symbols()), "array<i32, size>"); EXPECT_EQ(arr->FriendlyName(Symbols()), "array<i32, size>");
} }
TEST_F(AstArrayTest, FriendlyName_WithStride) { TEST_F(AstArrayTest, FriendlyName_WithStride) {
auto* i32 = create<I32>(); auto* i32 = create<I32>();
auto* arr = create<Array>(i32, Expr(5_u), AttributeList{create<StrideAttribute>(32u)}); auto* arr = create<Array>(i32, Expr(5_u), utils::Vector{create<StrideAttribute>(32u)});
EXPECT_EQ(arr->FriendlyName(Symbols()), "@stride(32) array<i32, 5>"); EXPECT_EQ(arr->FriendlyName(Symbols()), "@stride(32) array<i32, 5>");
} }
TEST_F(AstArrayTest, FriendlyName_InferredTypeAndCount) { TEST_F(AstArrayTest, FriendlyName_InferredTypeAndCount) {
auto* arr = create<Array>(nullptr, nullptr, AttributeList{}); auto* arr = create<Array>(nullptr, nullptr, utils::Empty);
EXPECT_EQ(arr->FriendlyName(Symbols()), "array"); EXPECT_EQ(arr->FriendlyName(Symbols()), "array");
} }
TEST_F(AstArrayTest, FriendlyName_InferredTypeAndCount_WithStrize) { TEST_F(AstArrayTest, FriendlyName_InferredTypeAndCount_WithStrize) {
auto* arr = create<Array>(nullptr, nullptr, AttributeList{create<StrideAttribute>(32u)}); auto* arr = create<Array>(nullptr, nullptr, utils::Vector{create<StrideAttribute>(32u)});
EXPECT_EQ(arr->FriendlyName(Symbols()), "@stride(32) array"); EXPECT_EQ(arr->FriendlyName(Symbols()), "@stride(32) array");
} }

View File

@ -38,13 +38,10 @@ class Attribute : public Castable<Attribute, Node> {
Attribute(ProgramID pid, NodeID nid, const Source& src) : Base(pid, nid, src) {} Attribute(ProgramID pid, NodeID nid, const Source& src) : Base(pid, nid, src) {}
}; };
/// A list of attributes
using AttributeList = std::vector<const Attribute*>;
/// @param attributes the list of attributes to search /// @param attributes the list of attributes to search
/// @returns true if `attributes` includes a attribute of type `T` /// @returns true if `attributes` includes a attribute of type `T`
template <typename... Ts> template <typename... Ts>
bool HasAttribute(const AttributeList& attributes) { bool HasAttribute(utils::VectorRef<const Attribute*> attributes) {
for (auto* attr : attributes) { for (auto* attr : attributes) {
if (attr->IsAnyOf<Ts...>()) { if (attr->IsAnyOf<Ts...>()) {
return true; return true;
@ -56,7 +53,7 @@ bool HasAttribute(const AttributeList& attributes) {
/// @param attributes the list of attributes to search /// @param attributes the list of attributes to search
/// @returns a pointer to `T` from `attributes` if found, otherwise nullptr. /// @returns a pointer to `T` from `attributes` if found, otherwise nullptr.
template <typename T> template <typename T>
const T* GetAttribute(const AttributeList& attributes) { const T* GetAttribute(utils::VectorRef<const Attribute*> attributes) {
for (auto* attr : attributes) { for (auto* attr : attributes) {
if (attr->Is<T>()) { if (attr->Is<T>()) {
return attr->As<T>(); return attr->As<T>();

View File

@ -23,7 +23,7 @@ namespace tint::ast {
BlockStatement::BlockStatement(ProgramID pid, BlockStatement::BlockStatement(ProgramID pid,
NodeID nid, NodeID nid,
const Source& src, const Source& src,
const StatementList& stmts) utils::VectorRef<const Statement*> stmts)
: Base(pid, nid, src), statements(std::move(stmts)) { : Base(pid, nid, src), statements(std::move(stmts)) {
for (auto* stmt : statements) { for (auto* stmt : statements) {
TINT_ASSERT(AST, stmt); TINT_ASSERT(AST, stmt);
@ -39,7 +39,7 @@ const BlockStatement* BlockStatement::Clone(CloneContext* ctx) const {
// Clone arguments outside of create() call to have deterministic ordering // Clone arguments outside of create() call to have deterministic ordering
auto src = ctx->Clone(source); auto src = ctx->Clone(source);
auto stmts = ctx->Clone(statements); auto stmts = ctx->Clone(statements);
return ctx->dst->create<BlockStatement>(src, stmts); return ctx->dst->create<BlockStatement>(src, std::move(stmts));
} }
} // namespace tint::ast } // namespace tint::ast

View File

@ -32,16 +32,16 @@ class BlockStatement final : public Castable<BlockStatement, Statement> {
BlockStatement(ProgramID pid, BlockStatement(ProgramID pid,
NodeID nid, NodeID nid,
const Source& source, const Source& source,
const StatementList& statements); utils::VectorRef<const Statement*> statements);
/// Move constructor /// Move constructor
BlockStatement(BlockStatement&&); BlockStatement(BlockStatement&&);
~BlockStatement() override; ~BlockStatement() override;
/// @returns true if the block has no statements /// @returns true if the block has no statements
bool Empty() const { return statements.empty(); } bool Empty() const { return statements.IsEmpty(); }
/// @returns the last statement in the block or nullptr if block empty /// @returns the last statement in the block or nullptr if block empty
const Statement* Last() const { return statements.empty() ? nullptr : statements.back(); } const Statement* Last() const { return statements.IsEmpty() ? nullptr : statements.Back(); }
/// Clones this node and all transitive child nodes using the `CloneContext` /// Clones this node and all transitive child nodes using the `CloneContext`
/// `ctx`. /// `ctx`.
@ -50,7 +50,7 @@ class BlockStatement final : public Castable<BlockStatement, Statement> {
const BlockStatement* Clone(CloneContext* ctx) const override; const BlockStatement* Clone(CloneContext* ctx) const override;
/// the statement list /// the statement list
const StatementList statements; const utils::Vector<const Statement*, 8> statements;
}; };
} // namespace tint::ast } // namespace tint::ast

View File

@ -26,21 +26,21 @@ TEST_F(BlockStatementTest, Creation) {
auto* d = create<DiscardStatement>(); auto* d = create<DiscardStatement>();
auto* ptr = d; auto* ptr = d;
auto* b = create<BlockStatement>(StatementList{d}); auto* b = create<BlockStatement>(utils::Vector{d});
ASSERT_EQ(b->statements.size(), 1u); ASSERT_EQ(b->statements.Length(), 1u);
EXPECT_EQ(b->statements[0], ptr); EXPECT_EQ(b->statements[0], ptr);
} }
TEST_F(BlockStatementTest, Creation_WithSource) { TEST_F(BlockStatementTest, Creation_WithSource) {
auto* b = create<BlockStatement>(Source{Source::Location{20, 2}}, ast::StatementList{}); auto* b = create<BlockStatement>(Source{Source::Location{20, 2}}, utils::Empty);
auto src = b->source; auto src = b->source;
EXPECT_EQ(src.range.begin.line, 20u); EXPECT_EQ(src.range.begin.line, 20u);
EXPECT_EQ(src.range.begin.column, 2u); EXPECT_EQ(src.range.begin.column, 2u);
} }
TEST_F(BlockStatementTest, IsBlock) { TEST_F(BlockStatementTest, IsBlock) {
auto* b = create<BlockStatement>(ast::StatementList{}); auto* b = create<BlockStatement>(utils::Empty);
EXPECT_TRUE(b->Is<BlockStatement>()); EXPECT_TRUE(b->Is<BlockStatement>());
} }
@ -48,7 +48,7 @@ TEST_F(BlockStatementTest, Assert_Null_Statement) {
EXPECT_FATAL_FAILURE( EXPECT_FATAL_FAILURE(
{ {
ProgramBuilder b; ProgramBuilder b;
b.create<BlockStatement>(ast::StatementList{nullptr}); b.create<BlockStatement>(utils::Vector<const ast::Statement*, 1>{nullptr});
}, },
"internal compiler error"); "internal compiler error");
} }
@ -58,7 +58,7 @@ TEST_F(BlockStatementTest, Assert_DifferentProgramID_Statement) {
{ {
ProgramBuilder b1; ProgramBuilder b1;
ProgramBuilder b2; ProgramBuilder b2;
b1.create<BlockStatement>(ast::StatementList{b2.create<DiscardStatement>()}); b1.create<BlockStatement>(utils::Vector{b2.create<DiscardStatement>()});
}, },
"internal compiler error"); "internal compiler error");
} }

View File

@ -29,7 +29,7 @@ TextureOverloadCase::TextureOverloadCase(ValidTextureOverload o,
ast::TextureDimension dims, ast::TextureDimension dims,
TextureDataType datatype, TextureDataType datatype,
const char* f, const char* f,
std::function<ExpressionList(ProgramBuilder*)> a) std::function<Args(ProgramBuilder*)> a)
: overload(o), : overload(o),
description(desc), description(desc),
texture_kind(tk), texture_kind(tk),
@ -44,7 +44,7 @@ TextureOverloadCase::TextureOverloadCase(ValidTextureOverload o,
ast::TextureDimension dims, ast::TextureDimension dims,
TextureDataType datatype, TextureDataType datatype,
const char* f, const char* f,
std::function<ExpressionList(ProgramBuilder*)> a) std::function<Args(ProgramBuilder*)> a)
: overload(o), : overload(o),
description(desc), description(desc),
texture_kind(tk), texture_kind(tk),
@ -59,7 +59,7 @@ TextureOverloadCase::TextureOverloadCase(ValidTextureOverload o,
ast::TextureDimension dims, ast::TextureDimension dims,
TextureDataType datatype, TextureDataType datatype,
const char* f, const char* f,
std::function<ExpressionList(ProgramBuilder*)> a) std::function<Args(ProgramBuilder*)> a)
: overload(o), : overload(o),
description(d), description(d),
texture_kind(TextureKind::kStorage), texture_kind(TextureKind::kStorage),
@ -141,7 +141,7 @@ const ast::Type* TextureOverloadCase::BuildResultVectorComponentType(ProgramBuil
} }
const ast::Variable* TextureOverloadCase::BuildTextureVariable(ProgramBuilder* b) const { const ast::Variable* TextureOverloadCase::BuildTextureVariable(ProgramBuilder* b) const {
AttributeList attrs = { utils::Vector attrs{
b->create<ast::GroupAttribute>(0u), b->create<ast::GroupAttribute>(0u),
b->create<ast::BindingAttribute>(0u), b->create<ast::BindingAttribute>(0u),
}; };
@ -175,7 +175,7 @@ const ast::Variable* TextureOverloadCase::BuildTextureVariable(ProgramBuilder* b
} }
const ast::Variable* TextureOverloadCase::BuildSamplerVariable(ProgramBuilder* b) const { const ast::Variable* TextureOverloadCase::BuildSamplerVariable(ProgramBuilder* b) const {
AttributeList attrs = { utils::Vector attrs = {
b->create<ast::GroupAttribute>(0u), b->create<ast::GroupAttribute>(0u),
b->create<ast::BindingAttribute>(1u), b->create<ast::BindingAttribute>(1u),
}; };

View File

@ -177,6 +177,9 @@ bool ReturnsVoid(ValidTextureOverload texture_overload);
/// Describes a texture builtin overload /// Describes a texture builtin overload
struct TextureOverloadCase { struct TextureOverloadCase {
/// Args is a list of ast::Expression used as arguments to the texture overload case.
using Args = utils::Vector<const ast::Expression*, 8>;
/// Constructor for textureSample...() functions /// Constructor for textureSample...() functions
TextureOverloadCase(ValidTextureOverload, TextureOverloadCase(ValidTextureOverload,
const char*, const char*,
@ -185,7 +188,7 @@ struct TextureOverloadCase {
ast::TextureDimension, ast::TextureDimension,
TextureDataType, TextureDataType,
const char*, const char*,
std::function<ExpressionList(ProgramBuilder*)>); std::function<Args(ProgramBuilder*)>);
/// Constructor for textureLoad() functions with non-storage textures /// Constructor for textureLoad() functions with non-storage textures
TextureOverloadCase(ValidTextureOverload, TextureOverloadCase(ValidTextureOverload,
const char*, const char*,
@ -193,7 +196,7 @@ struct TextureOverloadCase {
ast::TextureDimension, ast::TextureDimension,
TextureDataType, TextureDataType,
const char*, const char*,
std::function<ExpressionList(ProgramBuilder*)>); std::function<Args(ProgramBuilder*)>);
/// Constructor for textureLoad() with storage textures /// Constructor for textureLoad() with storage textures
TextureOverloadCase(ValidTextureOverload, TextureOverloadCase(ValidTextureOverload,
const char*, const char*,
@ -202,7 +205,7 @@ struct TextureOverloadCase {
ast::TextureDimension, ast::TextureDimension,
TextureDataType, TextureDataType,
const char*, const char*,
std::function<ExpressionList(ProgramBuilder*)>); std::function<Args(ProgramBuilder*)>);
/// Copy constructor /// Copy constructor
TextureOverloadCase(const TextureOverloadCase&); TextureOverloadCase(const TextureOverloadCase&);
/// Destructor /// Destructor
@ -246,7 +249,7 @@ struct TextureOverloadCase {
/// Name of the function. e.g. `textureSample`, `textureSampleGrad`, etc /// Name of the function. e.g. `textureSample`, `textureSampleGrad`, etc
const char* const function; const char* const function;
/// A function that builds the AST arguments for the overload /// A function that builds the AST arguments for the overload
std::function<ExpressionList(ProgramBuilder*)> const args; std::function<Args(ProgramBuilder*)> const args;
}; };
std::ostream& operator<<(std::ostream& out, const TextureOverloadCase& data); std::ostream& operator<<(std::ostream& out, const TextureOverloadCase& data);

View File

@ -14,6 +14,8 @@
#include "src/tint/ast/call_expression.h" #include "src/tint/ast/call_expression.h"
#include <utility>
#include "src/tint/program_builder.h" #include "src/tint/program_builder.h"
TINT_INSTANTIATE_TYPEINFO(tint::ast::CallExpression); TINT_INSTANTIATE_TYPEINFO(tint::ast::CallExpression);
@ -37,8 +39,8 @@ CallExpression::CallExpression(ProgramID pid,
NodeID nid, NodeID nid,
const Source& src, const Source& src,
const IdentifierExpression* name, const IdentifierExpression* name,
ExpressionList a) utils::VectorRef<const Expression*> a)
: Base(pid, nid, src), target(ToTarget(name)), args(a) { : Base(pid, nid, src), target(ToTarget(name)), args(std::move(a)) {
TINT_ASSERT(AST, name); TINT_ASSERT(AST, name);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, name, program_id); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, name, program_id);
for (auto* arg : args) { for (auto* arg : args) {
@ -51,8 +53,8 @@ CallExpression::CallExpression(ProgramID pid,
NodeID nid, NodeID nid,
const Source& src, const Source& src,
const Type* type, const Type* type,
ExpressionList a) utils::VectorRef<const Expression*> a)
: Base(pid, nid, src), target(ToTarget(type)), args(a) { : Base(pid, nid, src), target(ToTarget(type)), args(std::move(a)) {
TINT_ASSERT(AST, type); TINT_ASSERT(AST, type);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, type, program_id); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, type, program_id);
for (auto* arg : args) { for (auto* arg : args) {
@ -69,8 +71,9 @@ const CallExpression* CallExpression::Clone(CloneContext* ctx) const {
// Clone arguments outside of create() call to have deterministic ordering // Clone arguments outside of create() call to have deterministic ordering
auto src = ctx->Clone(source); auto src = ctx->Clone(source);
auto p = ctx->Clone(args); auto p = ctx->Clone(args);
return target.name ? ctx->dst->create<CallExpression>(src, ctx->Clone(target.name), p) return target.name
: ctx->dst->create<CallExpression>(src, ctx->Clone(target.type), p); ? ctx->dst->create<CallExpression>(src, ctx->Clone(target.name), std::move(p))
: ctx->dst->create<CallExpression>(src, ctx->Clone(target.type), std::move(p));
} }
} // namespace tint::ast } // namespace tint::ast

View File

@ -42,7 +42,7 @@ class CallExpression final : public Castable<CallExpression, Expression> {
NodeID nid, NodeID nid,
const Source& source, const Source& source,
const IdentifierExpression* name, const IdentifierExpression* name,
ExpressionList args); utils::VectorRef<const Expression*> args);
/// Constructor /// Constructor
/// @param pid the identifier of the program that owns this node /// @param pid the identifier of the program that owns this node
@ -54,7 +54,7 @@ class CallExpression final : public Castable<CallExpression, Expression> {
NodeID nid, NodeID nid,
const Source& source, const Source& source,
const Type* type, const Type* type,
ExpressionList args); utils::VectorRef<const Expression*> args);
/// Move constructor /// Move constructor
CallExpression(CallExpression&&); CallExpression(CallExpression&&);
@ -80,7 +80,7 @@ class CallExpression final : public Castable<CallExpression, Expression> {
const Target target; const Target target;
/// The arguments /// The arguments
const ExpressionList args; const utils::Vector<const Expression*, 8> args;
}; };
} // namespace tint::ast } // namespace tint::ast

View File

@ -22,23 +22,24 @@ using CallExpressionTest = TestHelper;
TEST_F(CallExpressionTest, CreationIdentifier) { TEST_F(CallExpressionTest, CreationIdentifier) {
auto* func = Expr("func"); auto* func = Expr("func");
ExpressionList params; utils::Vector params{
params.push_back(Expr("param1")); Expr("param1"),
params.push_back(Expr("param2")); Expr("param2"),
};
auto* stmt = create<CallExpression>(func, params); auto* stmt = create<CallExpression>(func, params);
EXPECT_EQ(stmt->target.name, func); EXPECT_EQ(stmt->target.name, func);
EXPECT_EQ(stmt->target.type, nullptr); EXPECT_EQ(stmt->target.type, nullptr);
const auto& vec = stmt->args; const auto& vec = stmt->args;
ASSERT_EQ(vec.size(), 2u); ASSERT_EQ(vec.Length(), 2u);
EXPECT_EQ(vec[0], params[0]); EXPECT_EQ(vec[0], params[0]);
EXPECT_EQ(vec[1], params[1]); EXPECT_EQ(vec[1], params[1]);
} }
TEST_F(CallExpressionTest, CreationIdentifier_WithSource) { TEST_F(CallExpressionTest, CreationIdentifier_WithSource) {
auto* func = Expr("func"); auto* func = Expr("func");
auto* stmt = create<CallExpression>(Source{{20, 2}}, func, ExpressionList{}); auto* stmt = create<CallExpression>(Source{{20, 2}}, func, utils::Empty);
EXPECT_EQ(stmt->target.name, func); EXPECT_EQ(stmt->target.name, func);
EXPECT_EQ(stmt->target.type, nullptr); EXPECT_EQ(stmt->target.type, nullptr);
@ -49,23 +50,24 @@ TEST_F(CallExpressionTest, CreationIdentifier_WithSource) {
TEST_F(CallExpressionTest, CreationType) { TEST_F(CallExpressionTest, CreationType) {
auto* type = ty.f32(); auto* type = ty.f32();
ExpressionList params; utils::Vector params{
params.push_back(Expr("param1")); Expr("param1"),
params.push_back(Expr("param2")); Expr("param2"),
};
auto* stmt = create<CallExpression>(type, params); auto* stmt = create<CallExpression>(type, params);
EXPECT_EQ(stmt->target.name, nullptr); EXPECT_EQ(stmt->target.name, nullptr);
EXPECT_EQ(stmt->target.type, type); EXPECT_EQ(stmt->target.type, type);
const auto& vec = stmt->args; const auto& vec = stmt->args;
ASSERT_EQ(vec.size(), 2u); ASSERT_EQ(vec.Length(), 2u);
EXPECT_EQ(vec[0], params[0]); EXPECT_EQ(vec[0], params[0]);
EXPECT_EQ(vec[1], params[1]); EXPECT_EQ(vec[1], params[1]);
} }
TEST_F(CallExpressionTest, CreationType_WithSource) { TEST_F(CallExpressionTest, CreationType_WithSource) {
auto* type = ty.f32(); auto* type = ty.f32();
auto* stmt = create<CallExpression>(Source{{20, 2}}, type, ExpressionList{}); auto* stmt = create<CallExpression>(Source{{20, 2}}, type, utils::Empty);
EXPECT_EQ(stmt->target.name, nullptr); EXPECT_EQ(stmt->target.name, nullptr);
EXPECT_EQ(stmt->target.type, type); EXPECT_EQ(stmt->target.type, type);
@ -76,7 +78,7 @@ TEST_F(CallExpressionTest, CreationType_WithSource) {
TEST_F(CallExpressionTest, IsCall) { TEST_F(CallExpressionTest, IsCall) {
auto* func = Expr("func"); auto* func = Expr("func");
auto* stmt = create<CallExpression>(func, ExpressionList{}); auto* stmt = create<CallExpression>(func, utils::Empty);
EXPECT_TRUE(stmt->Is<CallExpression>()); EXPECT_TRUE(stmt->Is<CallExpression>());
} }
@ -84,7 +86,7 @@ TEST_F(CallExpressionTest, Assert_Null_Identifier) {
EXPECT_FATAL_FAILURE( EXPECT_FATAL_FAILURE(
{ {
ProgramBuilder b; ProgramBuilder b;
b.create<CallExpression>(static_cast<IdentifierExpression*>(nullptr), ExpressionList{}); b.create<CallExpression>(static_cast<IdentifierExpression*>(nullptr), utils::Empty);
}, },
"internal compiler error"); "internal compiler error");
} }
@ -93,7 +95,7 @@ TEST_F(CallExpressionTest, Assert_Null_Type) {
EXPECT_FATAL_FAILURE( EXPECT_FATAL_FAILURE(
{ {
ProgramBuilder b; ProgramBuilder b;
b.create<CallExpression>(static_cast<Type*>(nullptr), ExpressionList{}); b.create<CallExpression>(static_cast<Type*>(nullptr), utils::Empty);
}, },
"internal compiler error"); "internal compiler error");
} }
@ -102,11 +104,11 @@ TEST_F(CallExpressionTest, Assert_Null_Param) {
EXPECT_FATAL_FAILURE( EXPECT_FATAL_FAILURE(
{ {
ProgramBuilder b; ProgramBuilder b;
ExpressionList params; b.create<CallExpression>(b.Expr("func"), utils::Vector{
params.push_back(b.Expr("param1")); b.Expr("param1"),
params.push_back(nullptr); nullptr,
params.push_back(b.Expr("param2")); b.Expr("param2"),
b.create<CallExpression>(b.Expr("func"), params); });
}, },
"internal compiler error"); "internal compiler error");
} }
@ -116,7 +118,7 @@ TEST_F(CallExpressionTest, Assert_DifferentProgramID_Identifier) {
{ {
ProgramBuilder b1; ProgramBuilder b1;
ProgramBuilder b2; ProgramBuilder b2;
b1.create<CallExpression>(b2.Expr("func"), ExpressionList{}); b1.create<CallExpression>(b2.Expr("func"), utils::Empty);
}, },
"internal compiler error"); "internal compiler error");
} }
@ -126,7 +128,7 @@ TEST_F(CallExpressionTest, Assert_DifferentProgramID_Type) {
{ {
ProgramBuilder b1; ProgramBuilder b1;
ProgramBuilder b2; ProgramBuilder b2;
b1.create<CallExpression>(b2.ty.f32(), ExpressionList{}); b1.create<CallExpression>(b2.ty.f32(), utils::Empty);
}, },
"internal compiler error"); "internal compiler error");
} }
@ -136,7 +138,7 @@ TEST_F(CallExpressionTest, Assert_DifferentProgramID_Param) {
{ {
ProgramBuilder b1; ProgramBuilder b1;
ProgramBuilder b2; ProgramBuilder b2;
b1.create<CallExpression>(b1.Expr("func"), ExpressionList{b2.Expr("param1")}); b1.create<CallExpression>(b1.Expr("func"), utils::Vector{b2.Expr("param1")});
}, },
"internal compiler error"); "internal compiler error");
} }

View File

@ -23,7 +23,7 @@ namespace {
using CallStatementTest = TestHelper; using CallStatementTest = TestHelper;
TEST_F(CallStatementTest, Creation) { TEST_F(CallStatementTest, Creation) {
auto* expr = create<CallExpression>(Expr("func"), ExpressionList{}); auto* expr = create<CallExpression>(Expr("func"), utils::Empty);
auto* c = create<CallStatement>(expr); auto* c = create<CallStatement>(expr);
EXPECT_EQ(c->expr, expr); EXPECT_EQ(c->expr, expr);
@ -48,7 +48,7 @@ TEST_F(CallStatementTest, Assert_DifferentProgramID_Call) {
{ {
ProgramBuilder b1; ProgramBuilder b1;
ProgramBuilder b2; ProgramBuilder b2;
b1.create<CallStatement>(b2.create<CallExpression>(b2.Expr("func"), ExpressionList{})); b1.create<CallStatement>(b2.create<CallExpression>(b2.Expr("func"), utils::Empty));
}, },
"internal compiler error"); "internal compiler error");
} }

View File

@ -14,6 +14,8 @@
#include "src/tint/ast/case_statement.h" #include "src/tint/ast/case_statement.h"
#include <utility>
#include "src/tint/program_builder.h" #include "src/tint/program_builder.h"
TINT_INSTANTIATE_TYPEINFO(tint::ast::CaseStatement); TINT_INSTANTIATE_TYPEINFO(tint::ast::CaseStatement);
@ -23,9 +25,9 @@ namespace tint::ast {
CaseStatement::CaseStatement(ProgramID pid, CaseStatement::CaseStatement(ProgramID pid,
NodeID nid, NodeID nid,
const Source& src, const Source& src,
CaseSelectorList s, utils::VectorRef<const IntLiteralExpression*> s,
const BlockStatement* b) const BlockStatement* b)
: Base(pid, nid, src), selectors(s), body(b) { : Base(pid, nid, src), selectors(std::move(s)), body(b) {
TINT_ASSERT(AST, body); TINT_ASSERT(AST, body);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, body, program_id); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, body, program_id);
for (auto* selector : selectors) { for (auto* selector : selectors) {
@ -43,7 +45,7 @@ const CaseStatement* CaseStatement::Clone(CloneContext* ctx) const {
auto src = ctx->Clone(source); auto src = ctx->Clone(source);
auto sel = ctx->Clone(selectors); auto sel = ctx->Clone(selectors);
auto* b = ctx->Clone(body); auto* b = ctx->Clone(body);
return ctx->dst->create<CaseStatement>(src, sel, b); return ctx->dst->create<CaseStatement>(src, std::move(sel), b);
} }
} // namespace tint::ast } // namespace tint::ast

View File

@ -22,9 +22,6 @@
namespace tint::ast { namespace tint::ast {
/// A list of case literals
using CaseSelectorList = std::vector<const IntLiteralExpression*>;
/// A case statement /// A case statement
class CaseStatement final : public Castable<CaseStatement, Statement> { class CaseStatement final : public Castable<CaseStatement, Statement> {
public: public:
@ -37,14 +34,14 @@ class CaseStatement final : public Castable<CaseStatement, Statement> {
CaseStatement(ProgramID pid, CaseStatement(ProgramID pid,
NodeID nid, NodeID nid,
const Source& src, const Source& src,
CaseSelectorList selectors, utils::VectorRef<const IntLiteralExpression*> selectors,
const BlockStatement* body); const BlockStatement* body);
/// Move constructor /// Move constructor
CaseStatement(CaseStatement&&); CaseStatement(CaseStatement&&);
~CaseStatement() override; ~CaseStatement() override;
/// @returns true if this is a default statement /// @returns true if this is a default statement
bool IsDefault() const { return selectors.empty(); } bool IsDefault() const { return selectors.IsEmpty(); }
/// Clones this node and all transitive child nodes using the `CloneContext` /// Clones this node and all transitive child nodes using the `CloneContext`
/// `ctx`. /// `ctx`.
@ -53,15 +50,12 @@ class CaseStatement final : public Castable<CaseStatement, Statement> {
const CaseStatement* Clone(CloneContext* ctx) const override; const CaseStatement* Clone(CloneContext* ctx) const override;
/// The case selectors, empty if none set /// The case selectors, empty if none set
const CaseSelectorList selectors; const utils::Vector<const IntLiteralExpression*, 4> selectors;
/// The case body /// The case body
const BlockStatement* const body; const BlockStatement* const body;
}; };
/// A list of case statements
using CaseStatementList = std::vector<const CaseStatement*>;
} // namespace tint::ast } // namespace tint::ast
#endif // SRC_TINT_AST_CASE_STATEMENT_H_ #endif // SRC_TINT_AST_CASE_STATEMENT_H_

View File

@ -27,40 +27,37 @@ namespace {
using CaseStatementTest = TestHelper; using CaseStatementTest = TestHelper;
TEST_F(CaseStatementTest, Creation_i32) { TEST_F(CaseStatementTest, Creation_i32) {
CaseSelectorList b;
auto* selector = Expr(2_i); auto* selector = Expr(2_i);
b.push_back(selector); utils::Vector b{selector};
auto* discard = create<DiscardStatement>(); auto* discard = create<DiscardStatement>();
auto* body = create<BlockStatement>(StatementList{discard}); auto* body = create<BlockStatement>(utils::Vector{discard});
auto* c = create<CaseStatement>(b, body); auto* c = create<CaseStatement>(b, body);
ASSERT_EQ(c->selectors.size(), 1u); ASSERT_EQ(c->selectors.Length(), 1u);
EXPECT_EQ(c->selectors[0], selector); EXPECT_EQ(c->selectors[0], selector);
ASSERT_EQ(c->body->statements.size(), 1u); ASSERT_EQ(c->body->statements.Length(), 1u);
EXPECT_EQ(c->body->statements[0], discard); EXPECT_EQ(c->body->statements[0], discard);
} }
TEST_F(CaseStatementTest, Creation_u32) { TEST_F(CaseStatementTest, Creation_u32) {
CaseSelectorList b;
auto* selector = Expr(2_u); auto* selector = Expr(2_u);
b.push_back(selector); utils::Vector b{selector};
auto* discard = create<DiscardStatement>(); auto* discard = create<DiscardStatement>();
auto* body = create<BlockStatement>(StatementList{discard}); auto* body = create<BlockStatement>(utils::Vector{discard});
auto* c = create<CaseStatement>(b, body); auto* c = create<CaseStatement>(b, body);
ASSERT_EQ(c->selectors.size(), 1u); ASSERT_EQ(c->selectors.Length(), 1u);
EXPECT_EQ(c->selectors[0], selector); EXPECT_EQ(c->selectors[0], selector);
ASSERT_EQ(c->body->statements.size(), 1u); ASSERT_EQ(c->body->statements.Length(), 1u);
EXPECT_EQ(c->body->statements[0], discard); EXPECT_EQ(c->body->statements[0], discard);
} }
TEST_F(CaseStatementTest, Creation_WithSource) { TEST_F(CaseStatementTest, Creation_WithSource) {
CaseSelectorList b; utils::Vector b{Expr(2_i)};
b.push_back(Expr(2_i));
auto* body = create<BlockStatement>(StatementList{ auto* body = create<BlockStatement>(utils::Vector{
create<DiscardStatement>(), create<DiscardStatement>(),
}); });
auto* c = create<CaseStatement>(Source{Source::Location{20, 2}}, b, body); auto* c = create<CaseStatement>(Source{Source::Location{20, 2}}, b, body);
@ -70,23 +67,21 @@ TEST_F(CaseStatementTest, Creation_WithSource) {
} }
TEST_F(CaseStatementTest, IsDefault_WithoutSelectors) { TEST_F(CaseStatementTest, IsDefault_WithoutSelectors) {
auto* body = create<BlockStatement>(StatementList{ auto* body = create<BlockStatement>(utils::Vector{
create<DiscardStatement>(), create<DiscardStatement>(),
}); });
auto* c = create<CaseStatement>(CaseSelectorList{}, body); auto* c = create<CaseStatement>(utils::Empty, body);
EXPECT_TRUE(c->IsDefault()); EXPECT_TRUE(c->IsDefault());
} }
TEST_F(CaseStatementTest, IsDefault_WithSelectors) { TEST_F(CaseStatementTest, IsDefault_WithSelectors) {
CaseSelectorList b; utils::Vector b{Expr(2_i)};
b.push_back(Expr(2_i)); auto* c = create<CaseStatement>(b, create<BlockStatement>(utils::Empty));
auto* c = create<CaseStatement>(b, create<BlockStatement>(StatementList{}));
EXPECT_FALSE(c->IsDefault()); EXPECT_FALSE(c->IsDefault());
} }
TEST_F(CaseStatementTest, IsCase) { TEST_F(CaseStatementTest, IsCase) {
auto* c = create<CaseStatement>(CaseSelectorList{}, create<BlockStatement>(StatementList{})); auto* c = create<CaseStatement>(utils::Empty, create<BlockStatement>(utils::Empty));
EXPECT_TRUE(c->Is<CaseStatement>()); EXPECT_TRUE(c->Is<CaseStatement>());
} }
@ -94,7 +89,7 @@ TEST_F(CaseStatementTest, Assert_Null_Body) {
EXPECT_FATAL_FAILURE( EXPECT_FATAL_FAILURE(
{ {
ProgramBuilder b; ProgramBuilder b;
b.create<CaseStatement>(CaseSelectorList{}, nullptr); b.create<CaseStatement>(utils::Empty, nullptr);
}, },
"internal compiler error"); "internal compiler error");
} }
@ -103,8 +98,8 @@ TEST_F(CaseStatementTest, Assert_Null_Selector) {
EXPECT_FATAL_FAILURE( EXPECT_FATAL_FAILURE(
{ {
ProgramBuilder b; ProgramBuilder b;
b.create<CaseStatement>(CaseSelectorList{nullptr}, b.create<CaseStatement>(utils::Vector<const ast::IntLiteralExpression*, 1>{nullptr},
b.create<BlockStatement>(StatementList{})); b.create<BlockStatement>(utils::Empty));
}, },
"internal compiler error"); "internal compiler error");
} }
@ -114,8 +109,7 @@ TEST_F(CaseStatementTest, Assert_DifferentProgramID_Call) {
{ {
ProgramBuilder b1; ProgramBuilder b1;
ProgramBuilder b2; ProgramBuilder b2;
b1.create<CaseStatement>(CaseSelectorList{}, b1.create<CaseStatement>(utils::Empty, b2.create<BlockStatement>(utils::Empty));
b2.create<BlockStatement>(StatementList{}));
}, },
"internal compiler error"); "internal compiler error");
} }
@ -125,8 +119,8 @@ TEST_F(CaseStatementTest, Assert_DifferentProgramID_Selector) {
{ {
ProgramBuilder b1; ProgramBuilder b1;
ProgramBuilder b2; ProgramBuilder b2;
b1.create<CaseStatement>(CaseSelectorList{b2.Expr(2_i)}, b1.create<CaseStatement>(utils::Vector{b2.Expr(2_i)},
b1.create<BlockStatement>(StatementList{})); b1.create<BlockStatement>(utils::Empty));
}, },
"internal compiler error"); "internal compiler error");
} }

View File

@ -14,6 +14,8 @@
#include "src/tint/ast/const.h" #include "src/tint/ast/const.h"
#include <utility>
#include "src/tint/program_builder.h" #include "src/tint/program_builder.h"
TINT_INSTANTIATE_TYPEINFO(tint::ast::Const); TINT_INSTANTIATE_TYPEINFO(tint::ast::Const);
@ -26,8 +28,8 @@ Const::Const(ProgramID pid,
const Symbol& sym, const Symbol& sym,
const ast::Type* ty, const ast::Type* ty,
const Expression* ctor, const Expression* ctor,
AttributeList attrs) utils::VectorRef<const Attribute*> attrs)
: Base(pid, nid, src, sym, ty, ctor, attrs) { : Base(pid, nid, src, sym, ty, ctor, std::move(attrs)) {
TINT_ASSERT(AST, ctor != nullptr); TINT_ASSERT(AST, ctor != nullptr);
} }
@ -45,7 +47,7 @@ const Const* Const::Clone(CloneContext* ctx) const {
auto* ty = ctx->Clone(type); auto* ty = ctx->Clone(type);
auto* ctor = ctx->Clone(constructor); auto* ctor = ctx->Clone(constructor);
auto attrs = ctx->Clone(attributes); auto attrs = ctx->Clone(attributes);
return ctx->dst->create<Const>(src, sym, ty, ctor, attrs); return ctx->dst->create<Const>(src, sym, ty, ctor, std::move(attrs));
} }
} // namespace tint::ast } // namespace tint::ast

View File

@ -46,7 +46,7 @@ class Const final : public Castable<Const, Variable> {
const Symbol& sym, const Symbol& sym,
const ast::Type* type, const ast::Type* type,
const Expression* constructor, const Expression* constructor,
AttributeList attributes); utils::VectorRef<const Attribute*> attributes);
/// Move constructor /// Move constructor
Const(Const&&); Const(Const&&);

View File

@ -52,9 +52,6 @@ class Enable final : public Castable<Enable, Node> {
const Extension extension; const Extension extension;
}; };
/// A list of enables
using EnableList = std::vector<const Enable*>;
} // namespace tint::ast } // namespace tint::ast
#endif // SRC_TINT_AST_ENABLE_H_ #endif // SRC_TINT_AST_ENABLE_H_

View File

@ -38,9 +38,6 @@ class Expression : public Castable<Expression, Node> {
Expression(Expression&&); Expression(Expression&&);
}; };
/// A list of expressions
using ExpressionList = std::vector<const Expression*>;
} // namespace tint::ast } // namespace tint::ast
#endif // SRC_TINT_AST_EXPRESSION_H_ #endif // SRC_TINT_AST_EXPRESSION_H_

View File

@ -26,11 +26,11 @@ Function::Function(ProgramID pid,
NodeID nid, NodeID nid,
const Source& src, const Source& src,
Symbol sym, Symbol sym,
ParameterList parameters, utils::VectorRef<const Parameter*> parameters,
const Type* return_ty, const Type* return_ty,
const BlockStatement* b, const BlockStatement* b,
AttributeList attrs, utils::VectorRef<const Attribute*> attrs,
AttributeList return_type_attrs) utils::VectorRef<const Attribute*> return_type_attrs)
: Base(pid, nid, src), : Base(pid, nid, src),
symbol(sym), symbol(sym),
params(std::move(parameters)), params(std::move(parameters)),

View File

@ -48,11 +48,11 @@ class Function final : public Castable<Function, Node> {
NodeID nid, NodeID nid,
const Source& source, const Source& source,
Symbol symbol, Symbol symbol,
ParameterList params, utils::VectorRef<const Parameter*> params,
const Type* return_type, const Type* return_type,
const BlockStatement* body, const BlockStatement* body,
AttributeList attributes, utils::VectorRef<const Attribute*> attributes,
AttributeList return_type_attributes); utils::VectorRef<const Attribute*> return_type_attributes);
/// Move constructor /// Move constructor
Function(Function&&); Function(Function&&);
@ -74,7 +74,7 @@ class Function final : public Castable<Function, Node> {
const Symbol symbol; const Symbol symbol;
/// The function params /// The function params
const ParameterList params; const utils::Vector<const Parameter*, 8> params;
/// The function return type /// The function return type
const Type* const return_type; const Type* const return_type;
@ -83,18 +83,18 @@ class Function final : public Castable<Function, Node> {
const BlockStatement* const body; const BlockStatement* const body;
/// The attributes attached to this function /// The attributes attached to this function
const AttributeList attributes; const utils::Vector<const Attribute*, 2> attributes;
/// The attributes attached to the function return type. /// The attributes attached to the function return type.
const AttributeList return_type_attributes; const utils::Vector<const Attribute*, 2> return_type_attributes;
}; };
/// A list of functions /// A list of functions
class FunctionList : public std::vector<const Function*> { class FunctionList : public utils::Vector<const Function*, 8> {
public: public:
/// Appends f to the end of the list /// Appends f to the end of the list
/// @param f the function to append to this list /// @param f the function to append to this list
void Add(const Function* f) { this->emplace_back(f); } void Add(const Function* f) { this->Push(f); }
/// Returns the function with the given name /// Returns the function with the given name
/// @param sym the function symbol to search for /// @param sym the function symbol to search for

View File

@ -26,20 +26,20 @@ namespace {
using FunctionTest = TestHelper; using FunctionTest = TestHelper;
TEST_F(FunctionTest, Creation) { TEST_F(FunctionTest, Creation) {
ParameterList params{Param("var", ty.i32())}; utils::Vector params{Param("var", ty.i32())};
auto* var = params[0]; auto* var = params[0];
auto* f = Func("func", params, ty.void_(), {}); auto* f = Func("func", params, ty.void_(), utils::Empty);
EXPECT_EQ(f->symbol, Symbols().Get("func")); EXPECT_EQ(f->symbol, Symbols().Get("func"));
ASSERT_EQ(f->params.size(), 1u); ASSERT_EQ(f->params.Length(), 1u);
EXPECT_TRUE(f->return_type->Is<ast::Void>()); EXPECT_TRUE(f->return_type->Is<ast::Void>());
EXPECT_EQ(f->params[0], var); EXPECT_EQ(f->params[0], var);
} }
TEST_F(FunctionTest, Creation_WithSource) { TEST_F(FunctionTest, Creation_WithSource) {
ParameterList params{Param("var", ty.i32())}; utils::Vector params{Param("var", ty.i32())};
auto* f = Func(Source{Source::Location{20, 2}}, "func", params, ty.void_(), {}); auto* f = Func(Source{Source::Location{20, 2}}, "func", params, ty.void_(), utils::Empty);
auto src = f->source; auto src = f->source;
EXPECT_EQ(src.range.begin.line, 20u); EXPECT_EQ(src.range.begin.line, 20u);
EXPECT_EQ(src.range.begin.column, 2u); EXPECT_EQ(src.range.begin.column, 2u);
@ -49,7 +49,7 @@ TEST_F(FunctionTest, Assert_InvalidName) {
EXPECT_FATAL_FAILURE( EXPECT_FATAL_FAILURE(
{ {
ProgramBuilder b; ProgramBuilder b;
b.Func("", {}, b.ty.void_(), {}); b.Func("", utils::Empty, b.ty.void_(), utils::Empty);
}, },
"internal compiler error"); "internal compiler error");
} }
@ -58,20 +58,20 @@ TEST_F(FunctionTest, Assert_Null_ReturnType) {
EXPECT_FATAL_FAILURE( EXPECT_FATAL_FAILURE(
{ {
ProgramBuilder b; ProgramBuilder b;
b.Func("f", {}, nullptr, {}); b.Func("f", utils::Empty, nullptr, utils::Empty);
}, },
"internal compiler error"); "internal compiler error");
} }
TEST_F(FunctionTest, Assert_Null_Param) { TEST_F(FunctionTest, Assert_Null_Param) {
using ParamList = utils::Vector<const ast::Parameter*, 2>;
EXPECT_FATAL_FAILURE( EXPECT_FATAL_FAILURE(
{ {
ProgramBuilder b; ProgramBuilder b;
ParameterList params; ParamList params;
params.push_back(b.Param("var", b.ty.i32())); params.Push(b.Param("var", b.ty.i32()));
params.push_back(nullptr); params.Push(nullptr);
b.Func("f", params, b.ty.void_(), utils::Empty);
b.Func("f", params, b.ty.void_(), {});
}, },
"internal compiler error"); "internal compiler error");
} }
@ -81,7 +81,7 @@ TEST_F(FunctionTest, Assert_DifferentProgramID_Symbol) {
{ {
ProgramBuilder b1; ProgramBuilder b1;
ProgramBuilder b2; ProgramBuilder b2;
b1.Func(b2.Sym("func"), {}, b1.ty.void_(), {}); b1.Func(b2.Sym("func"), utils::Empty, b1.ty.void_(), utils::Empty);
}, },
"internal compiler error"); "internal compiler error");
} }
@ -91,7 +91,11 @@ TEST_F(FunctionTest, Assert_DifferentProgramID_Param) {
{ {
ProgramBuilder b1; ProgramBuilder b1;
ProgramBuilder b2; ProgramBuilder b2;
b1.Func("func", {b2.Param("var", b2.ty.i32())}, b1.ty.void_(), {}); b1.Func("func",
utils::Vector{
b2.Param("var", b2.ty.i32()),
},
b1.ty.void_(), utils::Empty);
}, },
"internal compiler error"); "internal compiler error");
} }
@ -101,8 +105,8 @@ TEST_F(FunctionTest, Assert_DifferentProgramID_Attr) {
{ {
ProgramBuilder b1; ProgramBuilder b1;
ProgramBuilder b2; ProgramBuilder b2;
b1.Func("func", {}, b1.ty.void_(), {}, b1.Func("func", utils::Empty, b1.ty.void_(), utils::Empty,
{ utils::Vector{
b2.WorkgroupSize(2_i, 4_i, 6_i), b2.WorkgroupSize(2_i, 4_i, 6_i),
}); });
}, },
@ -114,8 +118,8 @@ TEST_F(FunctionTest, Assert_DifferentProgramID_ReturnAttr) {
{ {
ProgramBuilder b1; ProgramBuilder b1;
ProgramBuilder b2; ProgramBuilder b2;
b1.Func("func", {}, b1.ty.void_(), {}, {}, b1.Func("func", utils::Empty, b1.ty.void_(), utils::Empty, utils::Empty,
{ utils::Vector{
b2.WorkgroupSize(2_i, 4_i, 6_i), b2.WorkgroupSize(2_i, 4_i, 6_i),
}); });
}, },
@ -125,7 +129,7 @@ TEST_F(FunctionTest, Assert_DifferentProgramID_ReturnAttr) {
using FunctionListTest = TestHelper; using FunctionListTest = TestHelper;
TEST_F(FunctionListTest, FindSymbol) { TEST_F(FunctionListTest, FindSymbol) {
auto* func = Func("main", {}, ty.f32(), {}); auto* func = Func("main", utils::Empty, ty.f32(), utils::Empty);
FunctionList list; FunctionList list;
list.Add(func); list.Add(func);
EXPECT_EQ(func, list.Find(Symbols().Register("main"))); EXPECT_EQ(func, list.Find(Symbols().Register("main")));
@ -137,12 +141,12 @@ TEST_F(FunctionListTest, FindSymbolMissing) {
} }
TEST_F(FunctionListTest, FindSymbolStage) { TEST_F(FunctionListTest, FindSymbolStage) {
auto* fs = Func("main", {}, ty.f32(), {}, auto* fs = Func("main", utils::Empty, ty.f32(), utils::Empty,
{ utils::Vector{
Stage(PipelineStage::kFragment), Stage(PipelineStage::kFragment),
}); });
auto* vs = Func("main", {}, ty.f32(), {}, auto* vs = Func("main", utils::Empty, ty.f32(), utils::Empty,
{ utils::Vector{
Stage(PipelineStage::kVertex), Stage(PipelineStage::kVertex),
}); });
FunctionList list; FunctionList list;
@ -154,8 +158,8 @@ TEST_F(FunctionListTest, FindSymbolStage) {
TEST_F(FunctionListTest, FindSymbolStageMissing) { TEST_F(FunctionListTest, FindSymbolStageMissing) {
FunctionList list; FunctionList list;
list.Add(Func("main", {}, ty.f32(), {}, list.Add(Func("main", utils::Empty, ty.f32(), utils::Empty,
{ utils::Vector{
Stage(PipelineStage::kFragment), Stage(PipelineStage::kFragment),
})); }));
EXPECT_EQ(nullptr, list.Find(Symbols().Register("main"), PipelineStage::kVertex)); EXPECT_EQ(nullptr, list.Find(Symbols().Register("main"), PipelineStage::kVertex));
@ -163,8 +167,8 @@ TEST_F(FunctionListTest, FindSymbolStageMissing) {
TEST_F(FunctionListTest, HasStage) { TEST_F(FunctionListTest, HasStage) {
FunctionList list; FunctionList list;
list.Add(Func("main", {}, ty.f32(), {}, list.Add(Func("main", utils::Empty, ty.f32(), utils::Empty,
{ utils::Vector{
Stage(PipelineStage::kFragment), Stage(PipelineStage::kFragment),
})); }));
EXPECT_TRUE(list.HasStage(PipelineStage::kFragment)); EXPECT_TRUE(list.HasStage(PipelineStage::kFragment));

View File

@ -14,6 +14,8 @@
#include "src/tint/ast/let.h" #include "src/tint/ast/let.h"
#include <utility>
#include "src/tint/program_builder.h" #include "src/tint/program_builder.h"
TINT_INSTANTIATE_TYPEINFO(tint::ast::Let); TINT_INSTANTIATE_TYPEINFO(tint::ast::Let);
@ -26,8 +28,8 @@ Let::Let(ProgramID pid,
const Symbol& sym, const Symbol& sym,
const ast::Type* ty, const ast::Type* ty,
const Expression* ctor, const Expression* ctor,
AttributeList attrs) utils::VectorRef<const Attribute*> attrs)
: Base(pid, nid, src, sym, ty, ctor, attrs) { : Base(pid, nid, src, sym, ty, ctor, std::move(attrs)) {
TINT_ASSERT(AST, ctor != nullptr); TINT_ASSERT(AST, ctor != nullptr);
} }
@ -45,7 +47,7 @@ const Let* Let::Clone(CloneContext* ctx) const {
auto* ty = ctx->Clone(type); auto* ty = ctx->Clone(type);
auto* ctor = ctx->Clone(constructor); auto* ctor = ctx->Clone(constructor);
auto attrs = ctx->Clone(attributes); auto attrs = ctx->Clone(attributes);
return ctx->dst->create<Let>(src, sym, ty, ctor, attrs); return ctx->dst->create<Let>(src, sym, ty, ctor, std::move(attrs));
} }
} // namespace tint::ast } // namespace tint::ast

View File

@ -43,7 +43,7 @@ class Let final : public Castable<Let, Variable> {
const Symbol& sym, const Symbol& sym,
const ast::Type* type, const ast::Type* type,
const Expression* constructor, const Expression* constructor,
AttributeList attributes); utils::VectorRef<const Attribute*> attributes);
/// Move constructor /// Move constructor
Let(Let&&); Let(Let&&);

View File

@ -31,9 +31,9 @@ TEST_F(LoopStatementTest, Creation) {
auto* continuing = Block(create<DiscardStatement>()); auto* continuing = Block(create<DiscardStatement>());
auto* l = create<LoopStatement>(body, continuing); auto* l = create<LoopStatement>(body, continuing);
ASSERT_EQ(l->body->statements.size(), 1u); ASSERT_EQ(l->body->statements.Length(), 1u);
EXPECT_EQ(l->body->statements[0], b); EXPECT_EQ(l->body->statements[0], b);
ASSERT_EQ(l->continuing->statements.size(), 1u); ASSERT_EQ(l->continuing->statements.Length(), 1u);
EXPECT_EQ(l->continuing->statements[0], continuing->Last()); EXPECT_EQ(l->continuing->statements[0], continuing->Last());
} }

View File

@ -28,7 +28,7 @@ Module::Module(ProgramID pid, NodeID nid, const Source& src) : Base(pid, nid, sr
Module::Module(ProgramID pid, Module::Module(ProgramID pid,
NodeID nid, NodeID nid,
const Source& src, const Source& src,
std::vector<const ast::Node*> global_decls) utils::VectorRef<const ast::Node*> global_decls)
: Base(pid, nid, src), global_declarations_(std::move(global_decls)) { : Base(pid, nid, src), global_declarations_(std::move(global_decls)) {
for (auto* decl : global_declarations_) { for (auto* decl : global_declarations_) {
if (decl == nullptr) { if (decl == nullptr) {
@ -53,7 +53,7 @@ const ast::TypeDecl* Module::LookupType(Symbol name) const {
void Module::AddGlobalDeclaration(const tint::ast::Node* decl) { void Module::AddGlobalDeclaration(const tint::ast::Node* decl) {
diag::List diags; diag::List diags;
BinGlobalDeclaration(decl, diags); BinGlobalDeclaration(decl, diags);
global_declarations_.emplace_back(decl); global_declarations_.Push(decl);
} }
void Module::BinGlobalDeclaration(const tint::ast::Node* decl, diag::List& diags) { void Module::BinGlobalDeclaration(const tint::ast::Node* decl, diag::List& diags) {
@ -61,19 +61,19 @@ void Module::BinGlobalDeclaration(const tint::ast::Node* decl, diag::List& diags
decl, // decl, //
[&](const ast::TypeDecl* type) { [&](const ast::TypeDecl* type) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, type, program_id); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, type, program_id);
type_decls_.push_back(type); type_decls_.Push(type);
}, },
[&](const Function* func) { [&](const Function* func) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, func, program_id); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, func, program_id);
functions_.push_back(func); functions_.Push(func);
}, },
[&](const Variable* var) { [&](const Variable* var) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, var, program_id); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, var, program_id);
global_variables_.push_back(var); global_variables_.Push(var);
}, },
[&](const Enable* enable) { [&](const Enable* enable) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, enable, program_id); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, enable, program_id);
enables_.push_back(enable); enables_.Push(enable);
}, },
[&](Default) { TINT_ICE(AST, diags) << "Unknown global declaration type"; }); [&](Default) { TINT_ICE(AST, diags) << "Unknown global declaration type"; });
} }
@ -81,29 +81,29 @@ void Module::BinGlobalDeclaration(const tint::ast::Node* decl, diag::List& diags
void Module::AddEnable(const ast::Enable* enable) { void Module::AddEnable(const ast::Enable* enable) {
TINT_ASSERT(AST, enable); TINT_ASSERT(AST, enable);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, enable, program_id); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, enable, program_id);
global_declarations_.push_back(enable); global_declarations_.Push(enable);
enables_.push_back(enable); enables_.Push(enable);
} }
void Module::AddGlobalVariable(const ast::Variable* var) { void Module::AddGlobalVariable(const ast::Variable* var) {
TINT_ASSERT(AST, var); TINT_ASSERT(AST, var);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, var, program_id); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, var, program_id);
global_variables_.push_back(var); global_variables_.Push(var);
global_declarations_.push_back(var); global_declarations_.Push(var);
} }
void Module::AddTypeDecl(const ast::TypeDecl* type) { void Module::AddTypeDecl(const ast::TypeDecl* type) {
TINT_ASSERT(AST, type); TINT_ASSERT(AST, type);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, type, program_id); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, type, program_id);
type_decls_.push_back(type); type_decls_.Push(type);
global_declarations_.push_back(type); global_declarations_.Push(type);
} }
void Module::AddFunction(const ast::Function* func) { void Module::AddFunction(const ast::Function* func) {
TINT_ASSERT(AST, func); TINT_ASSERT(AST, func);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, func, program_id); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, func, program_id);
functions_.push_back(func); functions_.Push(func);
global_declarations_.push_back(func); global_declarations_.Push(func);
} }
const Module* Module::Clone(CloneContext* ctx) const { const Module* Module::Clone(CloneContext* ctx) const {
@ -117,10 +117,10 @@ void Module::Copy(CloneContext* ctx, const Module* src) {
// During the clone, declarations may have been placed into the module. // During the clone, declarations may have been placed into the module.
// Clear everything out, as we're about to re-bin the declarations. // Clear everything out, as we're about to re-bin the declarations.
type_decls_.clear(); type_decls_.Clear();
functions_.clear(); functions_.Clear();
global_variables_.clear(); global_variables_.Clear();
enables_.clear(); enables_.Clear();
for (auto* decl : global_declarations_) { for (auto* decl : global_declarations_) {
if (!decl) { if (!decl) {

View File

@ -16,11 +16,11 @@
#define SRC_TINT_AST_MODULE_H_ #define SRC_TINT_AST_MODULE_H_
#include <string> #include <string>
#include <vector>
#include "src/tint/ast/enable.h" #include "src/tint/ast/enable.h"
#include "src/tint/ast/function.h" #include "src/tint/ast/function.h"
#include "src/tint/ast/type.h" #include "src/tint/ast/type.h"
#include "src/tint/utils/vector.h"
namespace tint::ast { namespace tint::ast {
@ -42,13 +42,16 @@ class Module final : public Castable<Module, Node> {
/// @param src the source of this node /// @param src the source of this node
/// @param global_decls the list of global types, functions, and variables, in /// @param global_decls the list of global types, functions, and variables, in
/// the order they were declared in the source program /// the order they were declared in the source program
Module(ProgramID pid, NodeID nid, const Source& src, std::vector<const Node*> global_decls); Module(ProgramID pid,
NodeID nid,
const Source& src,
utils::VectorRef<const ast::Node*> global_decls);
/// Destructor /// Destructor
~Module() override; ~Module() override;
/// @returns the declaration-ordered global declarations for the module /// @returns the declaration-ordered global declarations for the module
const std::vector<const Node*>& GlobalDeclarations() const { return global_declarations_; } const auto& GlobalDeclarations() const { return global_declarations_; }
/// Add a enable directive to the Builder /// Add a enable directive to the Builder
/// @param ext the enable directive to add /// @param ext the enable directive to add
@ -74,26 +77,26 @@ class Module final : public Castable<Module, Node> {
void AddGlobalDeclaration(const tint::ast::Node* decl); void AddGlobalDeclaration(const tint::ast::Node* decl);
/// @returns the global variables for the module /// @returns the global variables for the module
const VariableList& GlobalVariables() const { return global_variables_; } const auto& GlobalVariables() const { return global_variables_; }
/// @returns the global variables for the module /// @returns the global variables for the module
VariableList& GlobalVariables() { return global_variables_; } auto& GlobalVariables() { return global_variables_; }
/// @returns the global variable declarations of kind 'T' for the module /// @returns the global variable declarations of kind 'T' for the module
template <typename T, typename = traits::EnableIfIsType<T, ast::Variable>> template <typename T, typename = traits::EnableIfIsType<T, ast::Variable>>
std::vector<const T*> Globals() const { auto Globals() const {
std::vector<const T*> out; utils::Vector<const T*, 32> out;
out.reserve(global_variables_.size()); out.Reserve(global_variables_.Length());
for (auto* global : global_variables_) { for (auto* global : global_variables_) {
if (auto* var = global->As<T>()) { if (auto* var = global->As<T>()) {
out.emplace_back(var); out.Push(var);
} }
} }
return out; return out;
} }
/// @returns the extension set for the module /// @returns the extension set for the module
const EnableList& Enables() const { return enables_; } const auto& Enables() const { return enables_; }
/// Adds a type declaration to the Builder. /// Adds a type declaration to the Builder.
/// @param decl the type declaration to add /// @param decl the type declaration to add
@ -104,7 +107,7 @@ class Module final : public Castable<Module, Node> {
const TypeDecl* LookupType(Symbol name) const; const TypeDecl* LookupType(Symbol name) const;
/// @returns the declared types in the module /// @returns the declared types in the module
const std::vector<const TypeDecl*>& TypeDecls() const { return type_decls_; } const auto& TypeDecls() const { return type_decls_; }
/// Add a function to the Builder /// Add a function to the Builder
/// @param func the function to add /// @param func the function to add
@ -131,11 +134,11 @@ class Module final : public Castable<Module, Node> {
/// * #functions_ /// * #functions_
void BinGlobalDeclaration(const tint::ast::Node* decl, diag::List& diags); void BinGlobalDeclaration(const tint::ast::Node* decl, diag::List& diags);
std::vector<const Node*> global_declarations_; utils::Vector<const Node*, 64> global_declarations_;
std::vector<const TypeDecl*> type_decls_; utils::Vector<const TypeDecl*, 16> type_decls_;
FunctionList functions_; FunctionList functions_;
VariableList global_variables_; utils::Vector<const Variable*, 32> global_variables_;
EnableList enables_; utils::Vector<const Enable*, 8> enables_;
}; };
} // namespace tint::ast } // namespace tint::ast

View File

@ -22,7 +22,7 @@ namespace {
using ModuleTest = TestHelper; using ModuleTest = TestHelper;
TEST_F(ModuleTest, Creation) { TEST_F(ModuleTest, Creation) {
EXPECT_EQ(Program(std::move(*this)).AST().Functions().size(), 0u); EXPECT_EQ(Program(std::move(*this)).AST().Functions().Length(), 0u);
} }
TEST_F(ModuleTest, LookupFunction) { TEST_F(ModuleTest, LookupFunction) {
@ -61,8 +61,8 @@ TEST_F(ModuleTest, Assert_DifferentProgramID_Function) {
ProgramBuilder b1; ProgramBuilder b1;
ProgramBuilder b2; ProgramBuilder b2;
b1.AST().AddFunction(b2.create<ast::Function>(b2.Symbols().Register("func"), b1.AST().AddFunction(b2.create<ast::Function>(b2.Symbols().Register("func"),
ParameterList{}, b2.ty.f32(), b2.Block(), utils::Empty, b2.ty.f32(), b2.Block(),
AttributeList{}, AttributeList{})); utils::Empty, utils::Empty));
}, },
"internal compiler error"); "internal compiler error");
} }
@ -116,7 +116,7 @@ TEST_F(ModuleTest, CloneOrder) {
ctx.Clone(); ctx.Clone();
auto& decls = cloned.AST().GlobalDeclarations(); auto& decls = cloned.AST().GlobalDeclarations();
ASSERT_EQ(decls.size(), 6u); ASSERT_EQ(decls.Length(), 6u);
EXPECT_TRUE(decls[1]->Is<ast::Function>()); EXPECT_TRUE(decls[1]->Is<ast::Function>());
EXPECT_TRUE(decls[3]->Is<ast::Alias>()); EXPECT_TRUE(decls[3]->Is<ast::Alias>());
EXPECT_TRUE(decls[5]->Is<ast::Variable>()); EXPECT_TRUE(decls[5]->Is<ast::Variable>());

View File

@ -14,6 +14,8 @@
#include "src/tint/ast/override.h" #include "src/tint/ast/override.h"
#include <utility>
#include "src/tint/program_builder.h" #include "src/tint/program_builder.h"
TINT_INSTANTIATE_TYPEINFO(tint::ast::Override); TINT_INSTANTIATE_TYPEINFO(tint::ast::Override);
@ -26,8 +28,8 @@ Override::Override(ProgramID pid,
const Symbol& sym, const Symbol& sym,
const ast::Type* ty, const ast::Type* ty,
const Expression* ctor, const Expression* ctor,
AttributeList attrs) utils::VectorRef<const Attribute*> attrs)
: Base(pid, nid, src, sym, ty, ctor, attrs) {} : Base(pid, nid, src, sym, ty, ctor, std::move(attrs)) {}
Override::Override(Override&&) = default; Override::Override(Override&&) = default;
@ -43,7 +45,7 @@ const Override* Override::Clone(CloneContext* ctx) const {
auto* ty = ctx->Clone(type); auto* ty = ctx->Clone(type);
auto* ctor = ctx->Clone(constructor); auto* ctor = ctx->Clone(constructor);
auto attrs = ctx->Clone(attributes); auto attrs = ctx->Clone(attributes);
return ctx->dst->create<Override>(src, sym, ty, ctor, attrs); return ctx->dst->create<Override>(src, sym, ty, ctor, std::move(attrs));
} }
std::string Override::Identifier(const SymbolTable& symbols) const { std::string Override::Identifier(const SymbolTable& symbols) const {

View File

@ -46,7 +46,7 @@ class Override final : public Castable<Override, Variable> {
const Symbol& sym, const Symbol& sym,
const ast::Type* type, const ast::Type* type,
const Expression* constructor, const Expression* constructor,
AttributeList attributes); utils::VectorRef<const Attribute*> attributes);
/// Move constructor /// Move constructor
Override(Override&&); Override(Override&&);

View File

@ -27,7 +27,7 @@ TEST_F(OverrideTest, Identifier_NoId) {
} }
TEST_F(OverrideTest, Identifier_WithId) { TEST_F(OverrideTest, Identifier_WithId) {
auto* o = Override("o", nullptr, Expr(f32(1.0)), {Id(4u)}); auto* o = Override("o", nullptr, Expr(f32(1.0)), utils::Vector{Id(4u)});
EXPECT_EQ(std::string("4"), o->Identifier(Symbols())); EXPECT_EQ(std::string("4"), o->Identifier(Symbols()));
} }

View File

@ -14,6 +14,8 @@
#include "src/tint/ast/parameter.h" #include "src/tint/ast/parameter.h"
#include <utility>
#include "src/tint/program_builder.h" #include "src/tint/program_builder.h"
TINT_INSTANTIATE_TYPEINFO(tint::ast::Parameter); TINT_INSTANTIATE_TYPEINFO(tint::ast::Parameter);
@ -25,8 +27,8 @@ Parameter::Parameter(ProgramID pid,
const Source& src, const Source& src,
const Symbol& sym, const Symbol& sym,
const ast::Type* ty, const ast::Type* ty,
AttributeList attrs) utils::VectorRef<const Attribute*> attrs)
: Base(pid, nid, src, sym, ty, nullptr, attrs) {} : Base(pid, nid, src, sym, ty, nullptr, std::move(attrs)) {}
Parameter::Parameter(Parameter&&) = default; Parameter::Parameter(Parameter&&) = default;
@ -41,7 +43,7 @@ const Parameter* Parameter::Clone(CloneContext* ctx) const {
auto sym = ctx->Clone(symbol); auto sym = ctx->Clone(symbol);
auto* ty = ctx->Clone(type); auto* ty = ctx->Clone(type);
auto attrs = ctx->Clone(attributes); auto attrs = ctx->Clone(attributes);
return ctx->dst->create<Parameter>(src, sym, ty, attrs); return ctx->dst->create<Parameter>(src, sym, ty, std::move(attrs));
} }
} // namespace tint::ast } // namespace tint::ast

View File

@ -45,7 +45,7 @@ class Parameter final : public Castable<Parameter, Variable> {
const Source& source, const Source& source,
const Symbol& sym, const Symbol& sym,
const ast::Type* type, const ast::Type* type,
AttributeList attributes); utils::VectorRef<const Attribute*> attributes);
/// Move constructor /// Move constructor
Parameter(Parameter&&); Parameter(Parameter&&);
@ -63,9 +63,6 @@ class Parameter final : public Castable<Parameter, Variable> {
const Parameter* Clone(CloneContext* ctx) const override; const Parameter* Clone(CloneContext* ctx) const override;
}; };
/// A list of parameters
using ParameterList = std::vector<const Parameter*>;
} // namespace tint::ast } // namespace tint::ast
#endif // SRC_TINT_AST_PARAMETER_H_ #endif // SRC_TINT_AST_PARAMETER_H_

View File

@ -39,9 +39,6 @@ class Statement : public Castable<Statement, Node> {
Statement(Statement&&); Statement(Statement&&);
}; };
/// A list of statements
using StatementList = std::vector<const Statement*>;
} // namespace tint::ast } // namespace tint::ast
#endif // SRC_TINT_AST_STATEMENT_H_ #endif // SRC_TINT_AST_STATEMENT_H_

View File

@ -26,8 +26,8 @@ Struct::Struct(ProgramID pid,
NodeID nid, NodeID nid,
const Source& src, const Source& src,
Symbol n, Symbol n,
StructMemberList m, utils::VectorRef<const ast::StructMember*> m,
AttributeList attrs) utils::VectorRef<const ast::Attribute*> attrs)
: Base(pid, nid, src, n), members(std::move(m)), attributes(std::move(attrs)) { : Base(pid, nid, src, n), members(std::move(m)), attributes(std::move(attrs)) {
for (auto* mem : members) { for (auto* mem : members) {
TINT_ASSERT(AST, mem); TINT_ASSERT(AST, mem);
@ -49,7 +49,7 @@ const Struct* Struct::Clone(CloneContext* ctx) const {
auto n = ctx->Clone(name); auto n = ctx->Clone(name);
auto mem = ctx->Clone(members); auto mem = ctx->Clone(members);
auto attrs = ctx->Clone(attributes); auto attrs = ctx->Clone(attributes);
return ctx->dst->create<Struct>(src, n, mem, attrs); return ctx->dst->create<Struct>(src, n, std::move(mem), std::move(attrs));
} }
} // namespace tint::ast } // namespace tint::ast

View File

@ -21,6 +21,7 @@
#include "src/tint/ast/attribute.h" #include "src/tint/ast/attribute.h"
#include "src/tint/ast/struct_member.h" #include "src/tint/ast/struct_member.h"
#include "src/tint/ast/type_decl.h" #include "src/tint/ast/type_decl.h"
#include "src/tint/utils/vector.h"
namespace tint::ast { namespace tint::ast {
@ -38,8 +39,8 @@ class Struct final : public Castable<Struct, TypeDecl> {
NodeID nid, NodeID nid,
const Source& src, const Source& src,
Symbol name, Symbol name,
StructMemberList members, utils::VectorRef<const ast::StructMember*> members,
AttributeList attributes); utils::VectorRef<const ast::Attribute*> attributes);
/// Move constructor /// Move constructor
Struct(Struct&&); Struct(Struct&&);
@ -52,10 +53,10 @@ class Struct final : public Castable<Struct, TypeDecl> {
const Struct* Clone(CloneContext* ctx) const override; const Struct* Clone(CloneContext* ctx) const override;
/// The members /// The members
const StructMemberList members; const utils::Vector<const ast::StructMember*, 8> members;
/// The struct attributes /// The struct attributes
const AttributeList attributes; const utils::Vector<const ast::Attribute*, 4> attributes;
}; };
} // namespace tint::ast } // namespace tint::ast

View File

@ -25,7 +25,7 @@ StructMember::StructMember(ProgramID pid,
const Source& src, const Source& src,
const Symbol& sym, const Symbol& sym,
const ast::Type* ty, const ast::Type* ty,
AttributeList attrs) utils::VectorRef<const Attribute*> attrs)
: Base(pid, nid, src), symbol(sym), type(ty), attributes(std::move(attrs)) { : Base(pid, nid, src), symbol(sym), type(ty), attributes(std::move(attrs)) {
TINT_ASSERT(AST, type); TINT_ASSERT(AST, type);
TINT_ASSERT(AST, symbol.IsValid()); TINT_ASSERT(AST, symbol.IsValid());
@ -46,7 +46,7 @@ const StructMember* StructMember::Clone(CloneContext* ctx) const {
auto sym = ctx->Clone(symbol); auto sym = ctx->Clone(symbol);
auto* ty = ctx->Clone(type); auto* ty = ctx->Clone(type);
auto attrs = ctx->Clone(attributes); auto attrs = ctx->Clone(attributes);
return ctx->dst->create<StructMember>(src, sym, ty, attrs); return ctx->dst->create<StructMember>(src, sym, ty, std::move(attrs));
} }
} // namespace tint::ast } // namespace tint::ast

View File

@ -16,7 +16,6 @@
#define SRC_TINT_AST_STRUCT_MEMBER_H_ #define SRC_TINT_AST_STRUCT_MEMBER_H_
#include <utility> #include <utility>
#include <vector>
#include "src/tint/ast/attribute.h" #include "src/tint/ast/attribute.h"
@ -42,7 +41,7 @@ class StructMember final : public Castable<StructMember, Node> {
const Source& src, const Source& src,
const Symbol& sym, const Symbol& sym,
const ast::Type* type, const ast::Type* type,
AttributeList attributes); utils::VectorRef<const Attribute*> attributes);
/// Move constructor /// Move constructor
StructMember(StructMember&&); StructMember(StructMember&&);
@ -61,12 +60,9 @@ class StructMember final : public Castable<StructMember, Node> {
const ast::Type* const type; const ast::Type* const type;
/// The attributes /// The attributes
const AttributeList attributes; const utils::Vector<const Attribute*, 4> attributes;
}; };
/// A list of struct members
using StructMemberList = std::vector<const StructMember*>;
} // namespace tint::ast } // namespace tint::ast
#endif // SRC_TINT_AST_STRUCT_MEMBER_H_ #endif // SRC_TINT_AST_STRUCT_MEMBER_H_

View File

@ -21,10 +21,10 @@ namespace {
using StructMemberTest = TestHelper; using StructMemberTest = TestHelper;
TEST_F(StructMemberTest, Creation) { TEST_F(StructMemberTest, Creation) {
auto* st = Member("a", ty.i32(), {MemberSize(4)}); auto* st = Member("a", ty.i32(), utils::Vector{MemberSize(4)});
EXPECT_EQ(st->symbol, Symbol(1, ID())); EXPECT_EQ(st->symbol, Symbol(1, ID()));
EXPECT_TRUE(st->type->Is<ast::I32>()); EXPECT_TRUE(st->type->Is<ast::I32>());
EXPECT_EQ(st->attributes.size(), 1u); EXPECT_EQ(st->attributes.Length(), 1u);
EXPECT_TRUE(st->attributes[0]->Is<StructMemberSizeAttribute>()); EXPECT_TRUE(st->attributes[0]->Is<StructMemberSizeAttribute>());
EXPECT_EQ(st->source.range.begin.line, 0u); EXPECT_EQ(st->source.range.begin.line, 0u);
EXPECT_EQ(st->source.range.begin.column, 0u); EXPECT_EQ(st->source.range.begin.column, 0u);
@ -37,7 +37,7 @@ TEST_F(StructMemberTest, CreationWithSource) {
ty.i32()); ty.i32());
EXPECT_EQ(st->symbol, Symbol(1, ID())); EXPECT_EQ(st->symbol, Symbol(1, ID()));
EXPECT_TRUE(st->type->Is<ast::I32>()); EXPECT_TRUE(st->type->Is<ast::I32>());
EXPECT_EQ(st->attributes.size(), 0u); EXPECT_EQ(st->attributes.Length(), 0u);
EXPECT_EQ(st->source.range.begin.line, 27u); EXPECT_EQ(st->source.range.begin.line, 27u);
EXPECT_EQ(st->source.range.begin.column, 4u); EXPECT_EQ(st->source.range.begin.column, 4u);
EXPECT_EQ(st->source.range.end.line, 27u); EXPECT_EQ(st->source.range.end.line, 27u);
@ -66,7 +66,7 @@ TEST_F(StructMemberTest, Assert_Null_Attribute) {
EXPECT_FATAL_FAILURE( EXPECT_FATAL_FAILURE(
{ {
ProgramBuilder b; ProgramBuilder b;
b.Member("a", b.ty.i32(), {b.MemberSize(4), nullptr}); b.Member("a", b.ty.i32(), utils::Vector{b.MemberSize(4), nullptr});
}, },
"internal compiler error"); "internal compiler error");
} }
@ -76,7 +76,7 @@ TEST_F(StructMemberTest, Assert_DifferentProgramID_Symbol) {
{ {
ProgramBuilder b1; ProgramBuilder b1;
ProgramBuilder b2; ProgramBuilder b2;
b1.Member(b2.Sym("a"), b1.ty.i32(), {b1.MemberSize(4)}); b1.Member(b2.Sym("a"), b1.ty.i32(), utils::Vector{b1.MemberSize(4)});
}, },
"internal compiler error"); "internal compiler error");
} }
@ -86,7 +86,7 @@ TEST_F(StructMemberTest, Assert_DifferentProgramID_Attribute) {
{ {
ProgramBuilder b1; ProgramBuilder b1;
ProgramBuilder b2; ProgramBuilder b2;
b1.Member("a", b1.ty.i32(), {b2.MemberSize(4)}); b1.Member("a", b1.ty.i32(), utils::Vector{b2.MemberSize(4)});
}, },
"internal compiler error"); "internal compiler error");
} }

View File

@ -36,10 +36,10 @@ using SpirvBlockAttribute = transform::AddSpirvBlockAttribute::SpirvBlockAttribu
TEST_F(AstStructTest, Creation) { TEST_F(AstStructTest, Creation) {
auto name = Sym("s"); auto name = Sym("s");
auto* s = create<Struct>(name, StructMemberList{Member("a", ty.i32())}, AttributeList{}); auto* s = create<Struct>(name, utils::Vector{Member("a", ty.i32())}, utils::Empty);
EXPECT_EQ(s->name, name); EXPECT_EQ(s->name, name);
EXPECT_EQ(s->members.size(), 1u); EXPECT_EQ(s->members.Length(), 1u);
EXPECT_TRUE(s->attributes.empty()); EXPECT_TRUE(s->attributes.IsEmpty());
EXPECT_EQ(s->source.range.begin.line, 0u); EXPECT_EQ(s->source.range.begin.line, 0u);
EXPECT_EQ(s->source.range.begin.column, 0u); EXPECT_EQ(s->source.range.begin.column, 0u);
EXPECT_EQ(s->source.range.end.line, 0u); EXPECT_EQ(s->source.range.end.line, 0u);
@ -48,13 +48,14 @@ TEST_F(AstStructTest, Creation) {
TEST_F(AstStructTest, Creation_WithAttributes) { TEST_F(AstStructTest, Creation_WithAttributes) {
auto name = Sym("s"); auto name = Sym("s");
AttributeList attrs;
attrs.push_back(ASTNodes().Create<SpirvBlockAttribute>(ID(), AllocateNodeID()));
auto* s = create<Struct>(name, StructMemberList{Member("a", ty.i32())}, attrs); auto* s = create<Struct>(name, utils::Vector{Member("a", ty.i32())},
utils::Vector{
ASTNodes().Create<SpirvBlockAttribute>(ID(), AllocateNodeID()),
});
EXPECT_EQ(s->name, name); EXPECT_EQ(s->name, name);
EXPECT_EQ(s->members.size(), 1u); EXPECT_EQ(s->members.Length(), 1u);
ASSERT_EQ(s->attributes.size(), 1u); ASSERT_EQ(s->attributes.Length(), 1u);
EXPECT_TRUE(s->attributes[0]->Is<SpirvBlockAttribute>()); EXPECT_TRUE(s->attributes[0]->Is<SpirvBlockAttribute>());
EXPECT_EQ(s->source.range.begin.line, 0u); EXPECT_EQ(s->source.range.begin.line, 0u);
EXPECT_EQ(s->source.range.begin.column, 0u); EXPECT_EQ(s->source.range.begin.column, 0u);
@ -66,11 +67,11 @@ TEST_F(AstStructTest, CreationWithSourceAndAttributes) {
auto name = Sym("s"); auto name = Sym("s");
auto* s = create<Struct>( auto* s = create<Struct>(
Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 8}}}, name, Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 8}}}, name,
StructMemberList{Member("a", ty.i32())}, utils::Vector{Member("a", ty.i32())},
AttributeList{ASTNodes().Create<SpirvBlockAttribute>(ID(), AllocateNodeID())}); utils::Vector{ASTNodes().Create<SpirvBlockAttribute>(ID(), AllocateNodeID())});
EXPECT_EQ(s->name, name); EXPECT_EQ(s->name, name);
EXPECT_EQ(s->members.size(), 1u); EXPECT_EQ(s->members.Length(), 1u);
ASSERT_EQ(s->attributes.size(), 1u); ASSERT_EQ(s->attributes.Length(), 1u);
EXPECT_TRUE(s->attributes[0]->Is<SpirvBlockAttribute>()); EXPECT_TRUE(s->attributes[0]->Is<SpirvBlockAttribute>());
EXPECT_EQ(s->source.range.begin.line, 27u); EXPECT_EQ(s->source.range.begin.line, 27u);
EXPECT_EQ(s->source.range.begin.column, 4u); EXPECT_EQ(s->source.range.begin.column, 4u);
@ -82,8 +83,8 @@ TEST_F(AstStructTest, Assert_Null_StructMember) {
EXPECT_FATAL_FAILURE( EXPECT_FATAL_FAILURE(
{ {
ProgramBuilder b; ProgramBuilder b;
b.create<Struct>(b.Sym("S"), StructMemberList{b.Member("a", b.ty.i32()), nullptr}, b.create<Struct>(b.Sym("S"), utils::Vector{b.Member("a", b.ty.i32()), nullptr},
AttributeList{}); utils::Empty);
}, },
"internal compiler error"); "internal compiler error");
} }
@ -92,8 +93,8 @@ TEST_F(AstStructTest, Assert_Null_Attribute) {
EXPECT_FATAL_FAILURE( EXPECT_FATAL_FAILURE(
{ {
ProgramBuilder b; ProgramBuilder b;
b.create<Struct>(b.Sym("S"), StructMemberList{b.Member("a", b.ty.i32())}, b.create<Struct>(b.Sym("S"), utils::Vector{b.Member("a", b.ty.i32())},
AttributeList{nullptr}); utils::Vector<const ast::Attribute*, 1>{nullptr});
}, },
"internal compiler error"); "internal compiler error");
} }
@ -103,8 +104,8 @@ TEST_F(AstStructTest, Assert_DifferentProgramID_StructMember) {
{ {
ProgramBuilder b1; ProgramBuilder b1;
ProgramBuilder b2; ProgramBuilder b2;
b1.create<Struct>(b1.Sym("S"), StructMemberList{b2.Member("a", b2.ty.i32())}, b1.create<Struct>(b1.Sym("S"), utils::Vector{b2.Member("a", b2.ty.i32())},
AttributeList{}); utils::Empty);
}, },
"internal compiler error"); "internal compiler error");
} }
@ -114,8 +115,8 @@ TEST_F(AstStructTest, Assert_DifferentProgramID_Attribute) {
{ {
ProgramBuilder b1; ProgramBuilder b1;
ProgramBuilder b2; ProgramBuilder b2;
b1.create<Struct>(b1.Sym("S"), StructMemberList{b1.Member("a", b1.ty.i32())}, b1.create<Struct>(b1.Sym("S"), utils::Vector{b1.Member("a", b1.ty.i32())},
AttributeList{b2.ASTNodes().Create<SpirvBlockAttribute>( utils::Vector{b2.ASTNodes().Create<SpirvBlockAttribute>(
b2.ID(), b2.AllocateNodeID())}); b2.ID(), b2.AllocateNodeID())});
}, },
"internal compiler error"); "internal compiler error");

View File

@ -14,6 +14,8 @@
#include "src/tint/ast/switch_statement.h" #include "src/tint/ast/switch_statement.h"
#include <utility>
#include "src/tint/program_builder.h" #include "src/tint/program_builder.h"
TINT_INSTANTIATE_TYPEINFO(tint::ast::SwitchStatement); TINT_INSTANTIATE_TYPEINFO(tint::ast::SwitchStatement);
@ -24,8 +26,8 @@ SwitchStatement::SwitchStatement(ProgramID pid,
NodeID nid, NodeID nid,
const Source& src, const Source& src,
const Expression* cond, const Expression* cond,
CaseStatementList b) utils::VectorRef<const CaseStatement*> b)
: Base(pid, nid, src), condition(cond), body(b) { : Base(pid, nid, src), condition(cond), body(std::move(b)) {
TINT_ASSERT(AST, condition); TINT_ASSERT(AST, condition);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, condition, program_id); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, condition, program_id);
for (auto* stmt : body) { for (auto* stmt : body) {
@ -43,7 +45,7 @@ const SwitchStatement* SwitchStatement::Clone(CloneContext* ctx) const {
auto src = ctx->Clone(source); auto src = ctx->Clone(source);
auto* cond = ctx->Clone(condition); auto* cond = ctx->Clone(condition);
auto b = ctx->Clone(body); auto b = ctx->Clone(body);
return ctx->dst->create<SwitchStatement>(src, cond, b); return ctx->dst->create<SwitchStatement>(src, cond, std::move(b));
} }
} // namespace tint::ast } // namespace tint::ast

View File

@ -33,7 +33,7 @@ class SwitchStatement final : public Castable<SwitchStatement, Statement> {
NodeID nid, NodeID nid,
const Source& src, const Source& src,
const Expression* condition, const Expression* condition,
CaseStatementList body); utils::VectorRef<const CaseStatement*> body);
/// Move constructor /// Move constructor
SwitchStatement(SwitchStatement&&); SwitchStatement(SwitchStatement&&);
~SwitchStatement() override; ~SwitchStatement() override;
@ -51,7 +51,7 @@ class SwitchStatement final : public Castable<SwitchStatement, Statement> {
const Expression* const condition; const Expression* const condition;
/// The Switch body /// The Switch body
const CaseStatementList body; const utils::Vector<const CaseStatement*, 4> body;
SwitchStatement(const SwitchStatement&) = delete; SwitchStatement(const SwitchStatement&) = delete;
}; };

View File

@ -25,54 +25,47 @@ namespace {
using SwitchStatementTest = TestHelper; using SwitchStatementTest = TestHelper;
TEST_F(SwitchStatementTest, Creation) { TEST_F(SwitchStatementTest, Creation) {
CaseSelectorList lit; auto* case_stmt = create<CaseStatement>(utils::Vector{Expr(1_u)}, Block());
lit.push_back(Expr(1_u));
auto* ident = Expr("ident"); auto* ident = Expr("ident");
CaseStatementList body; utils::Vector body{case_stmt};
auto* case_stmt = create<CaseStatement>(lit, Block());
body.push_back(case_stmt);
auto* stmt = create<SwitchStatement>(ident, body); auto* stmt = create<SwitchStatement>(ident, body);
EXPECT_EQ(stmt->condition, ident); EXPECT_EQ(stmt->condition, ident);
ASSERT_EQ(stmt->body.size(), 1u); ASSERT_EQ(stmt->body.Length(), 1u);
EXPECT_EQ(stmt->body[0], case_stmt); EXPECT_EQ(stmt->body[0], case_stmt);
} }
TEST_F(SwitchStatementTest, Creation_WithSource) { TEST_F(SwitchStatementTest, Creation_WithSource) {
auto* ident = Expr("ident"); auto* ident = Expr("ident");
auto* stmt = create<SwitchStatement>(Source{Source::Location{20, 2}}, ident, utils::Empty);
auto* stmt =
create<SwitchStatement>(Source{Source::Location{20, 2}}, ident, CaseStatementList());
auto src = stmt->source; auto src = stmt->source;
EXPECT_EQ(src.range.begin.line, 20u); EXPECT_EQ(src.range.begin.line, 20u);
EXPECT_EQ(src.range.begin.column, 2u); EXPECT_EQ(src.range.begin.column, 2u);
} }
TEST_F(SwitchStatementTest, IsSwitch) { TEST_F(SwitchStatementTest, IsSwitch) {
CaseSelectorList lit; utils::Vector lit{Expr(2_i)};
lit.push_back(Expr(2_i));
auto* ident = Expr("ident"); auto* ident = Expr("ident");
CaseStatementList body; utils::Vector body{create<CaseStatement>(lit, Block())};
body.push_back(create<CaseStatement>(lit, Block()));
auto* stmt = create<SwitchStatement>(ident, body); auto* stmt = create<SwitchStatement>(ident, body);
EXPECT_TRUE(stmt->Is<SwitchStatement>()); EXPECT_TRUE(stmt->Is<SwitchStatement>());
} }
TEST_F(SwitchStatementTest, Assert_Null_Condition) { TEST_F(SwitchStatementTest, Assert_Null_Condition) {
using CaseStatementList = utils::Vector<const ast::CaseStatement*, 2>;
EXPECT_FATAL_FAILURE( EXPECT_FATAL_FAILURE(
{ {
ProgramBuilder b; ProgramBuilder b;
CaseStatementList cases; CaseStatementList cases;
cases.push_back(b.create<CaseStatement>(CaseSelectorList{b.Expr(1_i)}, b.Block())); cases.Push(b.create<CaseStatement>(utils::Vector{b.Expr(1_i)}, b.Block()));
b.create<SwitchStatement>(nullptr, cases); b.create<SwitchStatement>(nullptr, cases);
}, },
"internal compiler error"); "internal compiler error");
} }
TEST_F(SwitchStatementTest, Assert_Null_CaseStatement) { TEST_F(SwitchStatementTest, Assert_Null_CaseStatement) {
using CaseStatementList = utils::Vector<const ast::CaseStatement*, 2>;
EXPECT_FATAL_FAILURE( EXPECT_FATAL_FAILURE(
{ {
ProgramBuilder b; ProgramBuilder b;
@ -86,9 +79,9 @@ TEST_F(SwitchStatementTest, Assert_DifferentProgramID_Condition) {
{ {
ProgramBuilder b1; ProgramBuilder b1;
ProgramBuilder b2; ProgramBuilder b2;
b1.create<SwitchStatement>(b2.Expr(true), CaseStatementList{ b1.create<SwitchStatement>(b2.Expr(true), utils::Vector{
b1.create<CaseStatement>( b1.create<CaseStatement>(
CaseSelectorList{ utils::Vector{
b1.Expr(1_i), b1.Expr(1_i),
}, },
b1.Block()), b1.Block()),
@ -102,9 +95,9 @@ TEST_F(SwitchStatementTest, Assert_DifferentProgramID_CaseStatement) {
{ {
ProgramBuilder b1; ProgramBuilder b1;
ProgramBuilder b2; ProgramBuilder b2;
b1.create<SwitchStatement>(b1.Expr(true), CaseStatementList{ b1.create<SwitchStatement>(b1.Expr(true), utils::Vector{
b2.create<CaseStatement>( b2.create<CaseStatement>(
CaseSelectorList{ utils::Vector{
b2.Expr(1_i), b2.Expr(1_i),
}, },
b2.Block()), b2.Block()),

View File

@ -82,7 +82,7 @@ bool TraverseExpressions(const ast::Expression* root, diag::List& diags, CALLBAC
to_visit.Push({right, depth}); to_visit.Push({right, depth});
} }
}; };
auto push_list = [&](const std::vector<const ast::Expression*>& exprs, size_t depth) { auto push_list = [&](utils::VectorRef<const ast::Expression*> exprs, size_t depth) {
if (ORDER == TraverseOrder::LeftToRight) { if (ORDER == TraverseOrder::LeftToRight) {
for (auto* expr : utils::Reverse(exprs)) { for (auto* expr : utils::Reverse(exprs)) {
to_visit.Push({expr, depth}); to_visit.Push({expr, depth});

View File

@ -97,19 +97,19 @@ TEST_F(TraverseExpressionsTest, DescendBitcastExpression) {
auto* b2 = Bitcast<i32>(b1); auto* b2 = Bitcast<i32>(b1);
auto* root = Bitcast<i32>(b2); auto* root = Bitcast<i32>(b2);
{ {
std::vector<const ast::Expression*> l2r; utils::Vector<const ast::Expression*, 8> l2r;
TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(), TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(),
[&](const ast::Expression* expr) { [&](const ast::Expression* expr) {
l2r.push_back(expr); l2r.Push(expr);
return ast::TraverseAction::Descend; return ast::TraverseAction::Descend;
}); });
EXPECT_THAT(l2r, ElementsAre(root, b2, b1, b0, e)); EXPECT_THAT(l2r, ElementsAre(root, b2, b1, b0, e));
} }
{ {
std::vector<const ast::Expression*> r2l; utils::Vector<const ast::Expression*, 8> r2l;
TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(), TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(),
[&](const ast::Expression* expr) { [&](const ast::Expression* expr) {
r2l.push_back(expr); r2l.Push(expr);
return ast::TraverseAction::Descend; return ast::TraverseAction::Descend;
}); });
EXPECT_THAT(r2l, ElementsAre(root, b2, b1, b0, e)); EXPECT_THAT(r2l, ElementsAre(root, b2, b1, b0, e));
@ -117,23 +117,23 @@ TEST_F(TraverseExpressionsTest, DescendBitcastExpression) {
} }
TEST_F(TraverseExpressionsTest, DescendCallExpression) { TEST_F(TraverseExpressionsTest, DescendCallExpression) {
std::vector<const ast::Expression*> e = {Expr(1_i), Expr(1_i), Expr(1_i), Expr(1_i)}; utils::Vector e{Expr(1_i), Expr(1_i), Expr(1_i), Expr(1_i)};
std::vector<const ast::Expression*> c = {Call("a", e[0], e[1]), Call("b", e[2], e[3])}; utils::Vector c{Call("a", e[0], e[1]), Call("b", e[2], e[3])};
auto* root = Call("c", c[0], c[1]); auto* root = Call("c", c[0], c[1]);
{ {
std::vector<const ast::Expression*> l2r; utils::Vector<const ast::Expression*, 8> l2r;
TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(), TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(),
[&](const ast::Expression* expr) { [&](const ast::Expression* expr) {
l2r.push_back(expr); l2r.Push(expr);
return ast::TraverseAction::Descend; return ast::TraverseAction::Descend;
}); });
EXPECT_THAT(l2r, ElementsAre(root, c[0], e[0], e[1], c[1], e[2], e[3])); EXPECT_THAT(l2r, ElementsAre(root, c[0], e[0], e[1], c[1], e[2], e[3]));
} }
{ {
std::vector<const ast::Expression*> r2l; utils::Vector<const ast::Expression*, 8> r2l;
TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(), TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(),
[&](const ast::Expression* expr) { [&](const ast::Expression* expr) {
r2l.push_back(expr); r2l.Push(expr);
return ast::TraverseAction::Descend; return ast::TraverseAction::Descend;
}); });
EXPECT_THAT(r2l, ElementsAre(root, c[1], e[3], e[2], c[0], e[1], e[0])); EXPECT_THAT(r2l, ElementsAre(root, c[1], e[3], e[2], c[0], e[1], e[0]));

View File

@ -28,8 +28,8 @@ Var::Var(ProgramID pid,
StorageClass storage_class, StorageClass storage_class,
Access access, Access access,
const Expression* ctor, const Expression* ctor,
AttributeList attrs) utils::VectorRef<const Attribute*> attrs)
: Base(pid, nid, src, sym, ty, ctor, attrs), : Base(pid, nid, src, sym, ty, ctor, std::move(attrs)),
declared_storage_class(storage_class), declared_storage_class(storage_class),
declared_access(access) {} declared_access(access) {}
@ -48,7 +48,7 @@ const Var* Var::Clone(CloneContext* ctx) const {
auto* ctor = ctx->Clone(constructor); auto* ctor = ctx->Clone(constructor);
auto attrs = ctx->Clone(attributes); auto attrs = ctx->Clone(attributes);
return ctx->dst->create<Var>(src, sym, ty, declared_storage_class, declared_access, ctor, return ctx->dst->create<Var>(src, sym, ty, declared_storage_class, declared_access, ctor,
attrs); std::move(attrs));
} }
} // namespace tint::ast } // namespace tint::ast

View File

@ -59,7 +59,7 @@ class Var final : public Castable<Var, Variable> {
StorageClass declared_storage_class, StorageClass declared_storage_class,
Access declared_access, Access declared_access,
const Expression* constructor, const Expression* constructor,
AttributeList attributes); utils::VectorRef<const Attribute*> attributes);
/// Move constructor /// Move constructor
Var(Var&&); Var(Var&&);

View File

@ -26,7 +26,7 @@ Variable::Variable(ProgramID pid,
const Symbol& sym, const Symbol& sym,
const ast::Type* ty, const ast::Type* ty,
const Expression* ctor, const Expression* ctor,
AttributeList attrs) utils::VectorRef<const Attribute*> attrs)
: Base(pid, nid, src), symbol(sym), type(ty), constructor(ctor), attributes(std::move(attrs)) { : Base(pid, nid, src), symbol(sym), type(ty), constructor(ctor), attributes(std::move(attrs)) {
TINT_ASSERT(AST, symbol.IsValid()); TINT_ASSERT(AST, symbol.IsValid());
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, symbol, program_id); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, symbol, program_id);

View File

@ -67,7 +67,7 @@ class Variable : public Castable<Variable, Node> {
const Symbol& sym, const Symbol& sym,
const ast::Type* type, const ast::Type* type,
const Expression* constructor, const Expression* constructor,
AttributeList attributes); utils::VectorRef<const Attribute*> attributes);
/// Move constructor /// Move constructor
Variable(Variable&&); Variable(Variable&&);
@ -95,12 +95,9 @@ class Variable : public Castable<Variable, Node> {
const Expression* const constructor; const Expression* const constructor;
/// The attributes attached to this variable /// The attributes attached to this variable
const AttributeList attributes; const utils::Vector<const Attribute*, 2> attributes;
}; };
/// A list of variables
using VariableList = std::vector<const Variable*>;
} // namespace tint::ast } // namespace tint::ast
#endif // SRC_TINT_AST_VARIABLE_H_ #endif // SRC_TINT_AST_VARIABLE_H_

View File

@ -38,7 +38,7 @@ TEST_F(VariableTest, Creation) {
TEST_F(VariableTest, CreationWithSource) { TEST_F(VariableTest, CreationWithSource) {
auto* v = Var(Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 5}}}, "i", auto* v = Var(Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 5}}}, "i",
ty.f32(), StorageClass::kPrivate, nullptr, AttributeList{}); ty.f32(), StorageClass::kPrivate, nullptr, utils::Empty);
EXPECT_EQ(v->symbol, Symbol(1, ID())); EXPECT_EQ(v->symbol, Symbol(1, ID()));
EXPECT_EQ(v->declared_storage_class, StorageClass::kPrivate); EXPECT_EQ(v->declared_storage_class, StorageClass::kPrivate);
@ -51,7 +51,7 @@ TEST_F(VariableTest, CreationWithSource) {
TEST_F(VariableTest, CreationEmpty) { TEST_F(VariableTest, CreationEmpty) {
auto* v = Var(Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 7}}}, "a_var", auto* v = Var(Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 7}}}, "a_var",
ty.i32(), StorageClass::kWorkgroup, nullptr, AttributeList{}); ty.i32(), StorageClass::kWorkgroup, nullptr, utils::Empty);
EXPECT_EQ(v->symbol, Symbol(1, ID())); EXPECT_EQ(v->symbol, Symbol(1, ID()));
EXPECT_EQ(v->declared_storage_class, StorageClass::kWorkgroup); EXPECT_EQ(v->declared_storage_class, StorageClass::kWorkgroup);
@ -93,7 +93,7 @@ TEST_F(VariableTest, Assert_DifferentProgramID_Constructor) {
TEST_F(VariableTest, WithAttributes) { TEST_F(VariableTest, WithAttributes) {
auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr, auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr,
AttributeList{ utils::Vector{
create<LocationAttribute>(1u), create<LocationAttribute>(1u),
create<BuiltinAttribute>(BuiltinValue::kPosition), create<BuiltinAttribute>(BuiltinValue::kPosition),
create<IdAttribute>(1200u), create<IdAttribute>(1200u),
@ -111,7 +111,7 @@ TEST_F(VariableTest, WithAttributes) {
TEST_F(VariableTest, BindingPoint) { TEST_F(VariableTest, BindingPoint) {
auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr, auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr,
AttributeList{ utils::Vector{
create<BindingAttribute>(2u), create<BindingAttribute>(2u),
create<GroupAttribute>(1u), create<GroupAttribute>(1u),
}); });
@ -123,7 +123,7 @@ TEST_F(VariableTest, BindingPoint) {
} }
TEST_F(VariableTest, BindingPointAttributes) { TEST_F(VariableTest, BindingPointAttributes) {
auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr, AttributeList{}); auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr, utils::Empty);
EXPECT_FALSE(var->BindingPoint()); EXPECT_FALSE(var->BindingPoint());
EXPECT_EQ(var->BindingPoint().group, nullptr); EXPECT_EQ(var->BindingPoint().group, nullptr);
EXPECT_EQ(var->BindingPoint().binding, nullptr); EXPECT_EQ(var->BindingPoint().binding, nullptr);
@ -131,7 +131,7 @@ TEST_F(VariableTest, BindingPointAttributes) {
TEST_F(VariableTest, BindingPointMissingGroupAttribute) { TEST_F(VariableTest, BindingPointMissingGroupAttribute) {
auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr, auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr,
AttributeList{ utils::Vector{
create<BindingAttribute>(2u), create<BindingAttribute>(2u),
}); });
EXPECT_FALSE(var->BindingPoint()); EXPECT_FALSE(var->BindingPoint());
@ -142,7 +142,7 @@ TEST_F(VariableTest, BindingPointMissingGroupAttribute) {
TEST_F(VariableTest, BindingPointMissingBindingAttribute) { TEST_F(VariableTest, BindingPointMissingBindingAttribute) {
auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr, auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr,
AttributeList{create<GroupAttribute>(1u)}); utils::Vector{create<GroupAttribute>(1u)});
EXPECT_FALSE(var->BindingPoint()); EXPECT_FALSE(var->BindingPoint());
ASSERT_NE(var->BindingPoint().group, nullptr); ASSERT_NE(var->BindingPoint().group, nullptr);
EXPECT_EQ(var->BindingPoint().group->value, 1u); EXPECT_EQ(var->BindingPoint().group->value, 1u);

View File

@ -62,7 +62,7 @@ void CloneContext::Clone() {
ast::FunctionList CloneContext::Clone(const ast::FunctionList& v) { ast::FunctionList CloneContext::Clone(const ast::FunctionList& v) {
ast::FunctionList out; ast::FunctionList out;
out.reserve(v.size()); out.Reserve(v.Length());
for (const ast::Function* el : v) { for (const ast::Function* el : v) {
out.Add(Clone(el)); out.Add(Clone(el));
} }

View File

@ -28,6 +28,7 @@
#include "src/tint/program_id.h" #include "src/tint/program_id.h"
#include "src/tint/symbol.h" #include "src/tint/symbol.h"
#include "src/tint/traits.h" #include "src/tint/traits.h"
#include "src/tint/utils/vector.h"
// Forward declarations // Forward declarations
namespace tint { namespace tint {
@ -163,12 +164,12 @@ class CloneContext {
/// ///
/// @param v the vector to clone /// @param v the vector to clone
/// @return the cloned vector /// @return the cloned vector
template <typename T, typename A> template <typename T, size_t N>
std::vector<T> Clone(const std::vector<T, A>& v) { utils::Vector<T, N> Clone(const utils::Vector<T, N>& v) {
std::vector<T> out; utils::Vector<T, N> out;
out.reserve(v.size()); out.reserve(v.size());
for (auto& el : v) { for (auto& el : v) {
out.emplace_back(Clone(el)); out.Push(Clone(el));
} }
return out; return out;
} }
@ -181,9 +182,9 @@ class CloneContext {
/// ///
/// @param v the vector to clone /// @param v the vector to clone
/// @return the cloned vector /// @return the cloned vector
template <typename T, typename A> template <typename T, size_t N>
std::vector<T*, A> Clone(const std::vector<T*, A>& v) { utils::Vector<T*, N> Clone(const utils::Vector<T*, N>& v) {
std::vector<T*, A> out; utils::Vector<T*, N> out;
Clone(out, v); Clone(out, v);
return out; return out;
} }
@ -196,39 +197,39 @@ class CloneContext {
/// ///
/// @param from the vector to clone /// @param from the vector to clone
/// @param to the cloned result /// @param to the cloned result
template <typename T, typename A> template <typename T, size_t N>
void Clone(std::vector<T*, A>& to, const std::vector<T*, A>& from) { void Clone(utils::Vector<T*, N>& to, const utils::Vector<T*, N>& from) {
to.reserve(from.size()); to.Reserve(from.Length());
auto list_transform_it = list_transforms_.find(&from); auto list_transform_it = list_transforms_.find(&from);
if (list_transform_it != list_transforms_.end()) { if (list_transform_it != list_transforms_.end()) {
const auto& transforms = list_transform_it->second; const auto& transforms = list_transform_it->second;
for (auto* o : transforms.insert_front_) { for (auto* o : transforms.insert_front_) {
to.emplace_back(CheckedCast<T>(o)); to.Push(CheckedCast<T>(o));
} }
for (auto& el : from) { for (auto& el : from) {
auto insert_before_it = transforms.insert_before_.find(el); auto insert_before_it = transforms.insert_before_.find(el);
if (insert_before_it != transforms.insert_before_.end()) { if (insert_before_it != transforms.insert_before_.end()) {
for (auto insert : insert_before_it->second) { for (auto insert : insert_before_it->second) {
to.emplace_back(CheckedCast<T>(insert)); to.Push(CheckedCast<T>(insert));
} }
} }
if (transforms.remove_.count(el) == 0) { if (transforms.remove_.count(el) == 0) {
to.emplace_back(Clone(el)); to.Push(Clone(el));
} }
auto insert_after_it = transforms.insert_after_.find(el); auto insert_after_it = transforms.insert_after_.find(el);
if (insert_after_it != transforms.insert_after_.end()) { if (insert_after_it != transforms.insert_after_.end()) {
for (auto insert : insert_after_it->second) { for (auto insert : insert_after_it->second) {
to.emplace_back(CheckedCast<T>(insert)); to.Push(CheckedCast<T>(insert));
} }
} }
} }
for (auto* o : transforms.insert_back_) { for (auto* o : transforms.insert_back_) {
to.emplace_back(CheckedCast<T>(o)); to.Push(CheckedCast<T>(o));
} }
} else { } else {
for (auto& el : from) { for (auto& el : from) {
to.emplace_back(Clone(el)); to.Push(Clone(el));
// Clone(el) may have inserted after // Clone(el) may have inserted after
list_transform_it = list_transforms_.find(&from); list_transform_it = list_transforms_.find(&from);
@ -238,7 +239,7 @@ class CloneContext {
auto insert_after_it = transforms.insert_after_.find(el); auto insert_after_it = transforms.insert_after_.find(el);
if (insert_after_it != transforms.insert_after_.end()) { if (insert_after_it != transforms.insert_after_.end()) {
for (auto insert : insert_after_it->second) { for (auto insert : insert_after_it->second) {
to.emplace_back(CheckedCast<T>(insert)); to.Push(CheckedCast<T>(insert));
} }
} }
} }
@ -250,7 +251,7 @@ class CloneContext {
const auto& transforms = list_transform_it->second; const auto& transforms = list_transform_it->second;
for (auto* o : transforms.insert_back_) { for (auto* o : transforms.insert_back_) {
to.emplace_back(CheckedCast<T>(o)); to.Push(CheckedCast<T>(o));
} }
} }
} }
@ -318,7 +319,7 @@ class CloneContext {
CloneableTransform transform; CloneableTransform transform;
transform.typeinfo = &TypeInfo::Of<T>(); transform.typeinfo = &TypeInfo::Of<T>();
transform.function = [=](const Cloneable* in) { return replacer(in->As<T>()); }; transform.function = [=](const Cloneable* in) { return replacer(in->As<T>()); };
transforms_.emplace_back(std::move(transform)); transforms_.Push(std::move(transform));
return *this; return *this;
} }
@ -386,8 +387,8 @@ class CloneContext {
/// @param object a pointer to the object in #src that will be omitted from /// @param object a pointer to the object in #src that will be omitted from
/// the cloned vector. /// the cloned vector.
/// @returns this CloneContext so calls can be chained /// @returns this CloneContext so calls can be chained
template <typename T, typename A, typename OBJECT> template <typename T, size_t N, typename OBJECT>
CloneContext& Remove(const std::vector<T, A>& vector, OBJECT* object) { CloneContext& Remove(const utils::Vector<T, N>& vector, OBJECT* object) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, object); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, object);
if (std::find(vector.begin(), vector.end(), object) == vector.end()) { if (std::find(vector.begin(), vector.end(), object) == vector.end()) {
TINT_ICE(Clone, Diagnostics()) TINT_ICE(Clone, Diagnostics())
@ -404,12 +405,12 @@ class CloneContext {
/// @param object a pointer to the object in #dst that will be inserted at the /// @param object a pointer to the object in #dst that will be inserted at the
/// front of the vector /// front of the vector
/// @returns this CloneContext so calls can be chained /// @returns this CloneContext so calls can be chained
template <typename T, typename A, typename OBJECT> template <typename T, size_t N, typename OBJECT>
CloneContext& InsertFront(const std::vector<T, A>& vector, OBJECT* object) { CloneContext& InsertFront(const utils::Vector<T, N>& vector, OBJECT* object) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, object); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, object);
auto& transforms = list_transforms_[&vector]; auto& transforms = list_transforms_[&vector];
auto& list = transforms.insert_front_; auto& list = transforms.insert_front_;
list.emplace_back(object); list.Push(object);
return *this; return *this;
} }
@ -418,12 +419,12 @@ class CloneContext {
/// @param object a pointer to the object in #dst that will be inserted at the /// @param object a pointer to the object in #dst that will be inserted at the
/// end of the vector /// end of the vector
/// @returns this CloneContext so calls can be chained /// @returns this CloneContext so calls can be chained
template <typename T, typename A, typename OBJECT> template <typename T, size_t N, typename OBJECT>
CloneContext& InsertBack(const std::vector<T, A>& vector, OBJECT* object) { CloneContext& InsertBack(const utils::Vector<T, N>& vector, OBJECT* object) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, object); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, object);
auto& transforms = list_transforms_[&vector]; auto& transforms = list_transforms_[&vector];
auto& list = transforms.insert_back_; auto& list = transforms.insert_back_;
list.emplace_back(object); list.Push(object);
return *this; return *this;
} }
@ -433,8 +434,8 @@ class CloneContext {
/// @param object a pointer to the object in #dst that will be inserted before /// @param object a pointer to the object in #dst that will be inserted before
/// any occurrence of the clone of `before` /// any occurrence of the clone of `before`
/// @returns this CloneContext so calls can be chained /// @returns this CloneContext so calls can be chained
template <typename T, typename A, typename BEFORE, typename OBJECT> template <typename T, size_t N, typename BEFORE, typename OBJECT>
CloneContext& InsertBefore(const std::vector<T, A>& vector, CloneContext& InsertBefore(const utils::Vector<T, N>& vector,
const BEFORE* before, const BEFORE* before,
const OBJECT* object) { const OBJECT* object) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, before); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, before);
@ -447,7 +448,7 @@ class CloneContext {
auto& transforms = list_transforms_[&vector]; auto& transforms = list_transforms_[&vector];
auto& list = transforms.insert_before_[before]; auto& list = transforms.insert_before_[before];
list.emplace_back(object); list.Push(object);
return *this; return *this;
} }
@ -457,8 +458,8 @@ class CloneContext {
/// @param object a pointer to the object in #dst that will be inserted after /// @param object a pointer to the object in #dst that will be inserted after
/// any occurrence of the clone of `after` /// any occurrence of the clone of `after`
/// @returns this CloneContext so calls can be chained /// @returns this CloneContext so calls can be chained
template <typename T, typename A, typename AFTER, typename OBJECT> template <typename T, size_t N, typename AFTER, typename OBJECT>
CloneContext& InsertAfter(const std::vector<T, A>& vector, CloneContext& InsertAfter(const utils::Vector<T, N>& vector,
const AFTER* after, const AFTER* after,
const OBJECT* object) { const OBJECT* object) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, after); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, after);
@ -471,7 +472,7 @@ class CloneContext {
auto& transforms = list_transforms_[&vector]; auto& transforms = list_transforms_[&vector];
auto& list = transforms.insert_after_[after]; auto& list = transforms.insert_after_[after];
list.emplace_back(object); list.Push(object);
return *this; return *this;
} }
@ -530,7 +531,7 @@ class CloneContext {
diag::List& Diagnostics() const; diag::List& Diagnostics() const;
/// A vector of const Cloneable* /// A vector of const Cloneable*
using CloneableList = std::vector<const Cloneable*>; using CloneableList = utils::Vector<const Cloneable*, 4>;
/// Transformations to be applied to a list (vector) /// Transformations to be applied to a list (vector)
struct ListTransforms { struct ListTransforms {
@ -551,12 +552,12 @@ class CloneContext {
CloneableList insert_back_; CloneableList insert_back_;
/// A map of object in #src to the list of cloned objects in #dst. /// A map of object in #src to the list of cloned objects in #dst.
/// Clone(const std::vector<T*>& v) will use this to insert the map-value /// Clone(const utils::Vector<T*>& v) will use this to insert the map-value
/// list into the target vector before cloning and inserting the map-key. /// list into the target vector before cloning and inserting the map-key.
std::unordered_map<const Cloneable*, CloneableList> insert_before_; std::unordered_map<const Cloneable*, CloneableList> insert_before_;
/// A map of object in #src to the list of cloned objects in #dst. /// A map of object in #src to the list of cloned objects in #dst.
/// Clone(const std::vector<T*>& v) will use this to insert the map-value /// Clone(const utils::Vector<T*>& v) will use this to insert the map-value
/// list into the target vector after cloning and inserting the map-key. /// list into the target vector after cloning and inserting the map-key.
std::unordered_map<const Cloneable*, CloneableList> insert_after_; std::unordered_map<const Cloneable*, CloneableList> insert_after_;
}; };
@ -569,9 +570,9 @@ class CloneContext {
std::unordered_map<Symbol, Symbol> cloned_symbols_; std::unordered_map<Symbol, Symbol> cloned_symbols_;
/// Cloneable transform functions registered with ReplaceAll() /// Cloneable transform functions registered with ReplaceAll()
std::vector<CloneableTransform> transforms_; utils::Vector<CloneableTransform, 8> transforms_;
/// Map of std::vector pointer to transforms for that list /// Map of utils::Vector pointer to transforms for that list
std::unordered_map<const void*, ListTransforms> list_transforms_; std::unordered_map<const void*, ListTransforms> list_transforms_;
/// Symbol transform registered with ReplaceAll() /// Symbol transform registered with ReplaceAll()

View File

@ -37,12 +37,13 @@ struct Node : public Castable<Node, Cloneable> {
const Node* node_b = nullptr, const Node* node_b = nullptr,
const Node* node_c = nullptr) const Node* node_c = nullptr)
: allocator(alloc), name(n), a(node_a), b(node_b), c(node_c) {} : allocator(alloc), name(n), a(node_a), b(node_b), c(node_c) {}
Node(Node&&) = delete;
Allocator* const allocator; Allocator* const allocator;
Symbol name; Symbol name;
const Node* a = nullptr; const Node* a = nullptr;
const Node* b = nullptr; const Node* b = nullptr;
const Node* c = nullptr; const Node* c = nullptr;
std::vector<const Node*> vec; utils::Vector<const Node*, 8> vec;
Node* Clone(CloneContext* ctx) const override { Node* Clone(CloneContext* ctx) const override {
auto* out = allocator->Create<Node>(ctx->Clone(name)); auto* out = allocator->Create<Node>(ctx->Clone(name));
@ -387,7 +388,7 @@ TEST_F(CloneContextNodeTest, CloneWithRemove) {
.Remove(original_root->vec, original_root->vec[1]) .Remove(original_root->vec, original_root->vec[1])
.Clone(original_root); .Clone(original_root);
EXPECT_EQ(cloned_root->vec.size(), 2u); EXPECT_EQ(cloned_root->vec.Length(), 2u);
EXPECT_NE(cloned_root->vec[0], cloned_root->a); EXPECT_NE(cloned_root->vec[0], cloned_root->a);
EXPECT_NE(cloned_root->vec[1], cloned_root->c); EXPECT_NE(cloned_root->vec[1], cloned_root->c);
@ -416,7 +417,7 @@ TEST_F(CloneContextNodeTest, CloneWithInsertFront) {
.InsertFront(original_root->vec, insertion) .InsertFront(original_root->vec, insertion)
.Clone(original_root); .Clone(original_root);
EXPECT_EQ(cloned_root->vec.size(), 4u); EXPECT_EQ(cloned_root->vec.Length(), 4u);
EXPECT_NE(cloned_root->vec[0], cloned_root->a); EXPECT_NE(cloned_root->vec[0], cloned_root->a);
EXPECT_NE(cloned_root->vec[1], cloned_root->b); EXPECT_NE(cloned_root->vec[1], cloned_root->b);
@ -434,7 +435,7 @@ TEST_F(CloneContextNodeTest, CloneWithInsertFront_Empty) {
ProgramBuilder builder; ProgramBuilder builder;
auto* original_root = a.Create<Node>(builder.Symbols().Register("root")); auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
original_root->vec = {}; original_root->vec.Clear();
Program original(std::move(builder)); Program original(std::move(builder));
ProgramBuilder cloned; ProgramBuilder cloned;
@ -444,7 +445,7 @@ TEST_F(CloneContextNodeTest, CloneWithInsertFront_Empty) {
.InsertFront(original_root->vec, insertion) .InsertFront(original_root->vec, insertion)
.Clone(original_root); .Clone(original_root);
EXPECT_EQ(cloned_root->vec.size(), 1u); EXPECT_EQ(cloned_root->vec.Length(), 1u);
EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root")); EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion")); EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion"));
@ -469,7 +470,7 @@ TEST_F(CloneContextNodeTest, CloneWithInsertBack) {
.InsertBack(original_root->vec, insertion) .InsertBack(original_root->vec, insertion)
.Clone(original_root); .Clone(original_root);
EXPECT_EQ(cloned_root->vec.size(), 4u); EXPECT_EQ(cloned_root->vec.Length(), 4u);
EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root")); EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a")); EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
@ -483,7 +484,7 @@ TEST_F(CloneContextNodeTest, CloneWithInsertBack_Empty) {
ProgramBuilder builder; ProgramBuilder builder;
auto* original_root = a.Create<Node>(builder.Symbols().Register("root")); auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
original_root->vec = {}; original_root->vec.Clear();
Program original(std::move(builder)); Program original(std::move(builder));
ProgramBuilder cloned; ProgramBuilder cloned;
@ -493,7 +494,7 @@ TEST_F(CloneContextNodeTest, CloneWithInsertBack_Empty) {
.InsertBack(original_root->vec, insertion) .InsertBack(original_root->vec, insertion)
.Clone(original_root); .Clone(original_root);
EXPECT_EQ(cloned_root->vec.size(), 1u); EXPECT_EQ(cloned_root->vec.Length(), 1u);
EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root")); EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion")); EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion"));
@ -504,7 +505,7 @@ TEST_F(CloneContextNodeTest, CloneWithInsertFrontAndBack_Empty) {
ProgramBuilder builder; ProgramBuilder builder;
auto* original_root = a.Create<Node>(builder.Symbols().Register("root")); auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
original_root->vec = {}; original_root->vec.Clear();
Program original(std::move(builder)); Program original(std::move(builder));
ProgramBuilder cloned; ProgramBuilder cloned;
@ -516,7 +517,7 @@ TEST_F(CloneContextNodeTest, CloneWithInsertFrontAndBack_Empty) {
.InsertFront(original_root->vec, insertion_front) .InsertFront(original_root->vec, insertion_front)
.Clone(original_root); .Clone(original_root);
EXPECT_EQ(cloned_root->vec.size(), 2u); EXPECT_EQ(cloned_root->vec.Length(), 2u);
EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root")); EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion_front")); EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion_front"));
@ -542,7 +543,7 @@ TEST_F(CloneContextNodeTest, CloneWithInsertBefore) {
.InsertBefore(original_root->vec, original_root->vec[1], insertion) .InsertBefore(original_root->vec, original_root->vec[1], insertion)
.Clone(original_root); .Clone(original_root);
EXPECT_EQ(cloned_root->vec.size(), 4u); EXPECT_EQ(cloned_root->vec.Length(), 4u);
EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root")); EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a")); EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
@ -570,7 +571,7 @@ TEST_F(CloneContextNodeTest, CloneWithInsertAfter) {
.InsertAfter(original_root->vec, original_root->vec[1], insertion) .InsertAfter(original_root->vec, original_root->vec[1], insertion)
.Clone(original_root); .Clone(original_root);
EXPECT_EQ(cloned_root->vec.size(), 4u); EXPECT_EQ(cloned_root->vec.Length(), 4u);
EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root")); EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a")); EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
@ -602,7 +603,7 @@ TEST_F(CloneContextNodeTest, CloneWithInsertAfterInVectorNodeClone) {
auto* cloned_root = ctx.Clone(original_root); auto* cloned_root = ctx.Clone(original_root);
EXPECT_EQ(cloned_root->vec.size(), 4u); EXPECT_EQ(cloned_root->vec.Length(), 4u);
EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root")); EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a")); EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
@ -634,7 +635,7 @@ TEST_F(CloneContextNodeTest, CloneWithInsertBackInVectorNodeClone) {
auto* cloned_root = ctx.Clone(original_root); auto* cloned_root = ctx.Clone(original_root);
EXPECT_EQ(cloned_root->vec.size(), 4u); EXPECT_EQ(cloned_root->vec.Length(), 4u);
EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root")); EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a")); EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
@ -666,7 +667,7 @@ TEST_F(CloneContextNodeTest, CloneWithInsertBeforeAndAfterRemoved) {
.Remove(original_root->vec, original_root->vec[1]) .Remove(original_root->vec, original_root->vec[1])
.Clone(original_root); .Clone(original_root);
EXPECT_EQ(cloned_root->vec.size(), 4u); EXPECT_EQ(cloned_root->vec.Length(), 4u);
EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root")); EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a")); EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));

View File

@ -107,7 +107,7 @@ std::tuple<ComponentType, CompositionType> CalculateComponentAndComposition(cons
std::tuple<InterpolationType, InterpolationSampling> CalculateInterpolationData( std::tuple<InterpolationType, InterpolationSampling> CalculateInterpolationData(
const sem::Type* type, const sem::Type* type,
const ast::AttributeList& attributes) { utils::VectorRef<const ast::Attribute*> attributes) {
auto* interpolation_attribute = ast::GetAttribute<ast::InterpolateAttribute>(attributes); auto* interpolation_attribute = ast::GetAttribute<ast::InterpolateAttribute>(attributes);
if (type->is_integer_scalar_or_vector()) { if (type->is_integer_scalar_or_vector()) {
return {InterpolationType::kFlat, InterpolationSampling::kNone}; return {InterpolationType::kFlat, InterpolationSampling::kNone};
@ -608,7 +608,7 @@ const ast::Function* Inspector::FindEntryPointByName(const std::string& name) {
void Inspector::AddEntryPointInOutVariables(std::string name, void Inspector::AddEntryPointInOutVariables(std::string name,
const sem::Type* type, const sem::Type* type,
const ast::AttributeList& attributes, utils::VectorRef<const ast::Attribute*> attributes,
std::vector<StageVariable>& variables) const { std::vector<StageVariable>& variables) const {
// Skip builtins. // Skip builtins.
if (ast::HasAttribute<ast::BuiltinAttribute>(attributes)) { if (ast::HasAttribute<ast::BuiltinAttribute>(attributes)) {
@ -647,7 +647,7 @@ void Inspector::AddEntryPointInOutVariables(std::string name,
bool Inspector::ContainsBuiltin(ast::BuiltinValue builtin, bool Inspector::ContainsBuiltin(ast::BuiltinValue builtin,
const sem::Type* type, const sem::Type* type,
const ast::AttributeList& attributes) const { utils::VectorRef<const ast::Attribute*> attributes) const {
auto* unwrapped_type = type->UnwrapRef(); auto* unwrapped_type = type->UnwrapRef();
if (auto* struct_ty = unwrapped_type->As<sem::Struct>()) { if (auto* struct_ty = unwrapped_type->As<sem::Struct>()) {

View File

@ -170,7 +170,7 @@ class Inspector {
/// @param variables the list to add the variables to /// @param variables the list to add the variables to
void AddEntryPointInOutVariables(std::string name, void AddEntryPointInOutVariables(std::string name,
const sem::Type* type, const sem::Type* type,
const ast::AttributeList& attributes, utils::VectorRef<const ast::Attribute*> attributes,
std::vector<StageVariable>& variables) const; std::vector<StageVariable>& variables) const;
/// Recursively determine if the type contains builtin. /// Recursively determine if the type contains builtin.
@ -178,7 +178,7 @@ class Inspector {
/// Otherwise, check `attributes` for the attribute. /// Otherwise, check `attributes` for the attribute.
bool ContainsBuiltin(ast::BuiltinValue builtin, bool ContainsBuiltin(ast::BuiltinValue builtin,
const sem::Type* type, const sem::Type* type,
const ast::AttributeList& attributes) const; utils::VectorRef<const ast::Attribute*> attributes) const;
/// Gathers all the texture resource bindings of the given type for the given /// Gathers all the texture resource bindings of the given type for the given
/// entry point. /// entry point.

File diff suppressed because it is too large Load Diff

View File

@ -27,32 +27,36 @@ namespace tint::inspector {
InspectorBuilder::InspectorBuilder() = default; InspectorBuilder::InspectorBuilder() = default;
InspectorBuilder::~InspectorBuilder() = default; InspectorBuilder::~InspectorBuilder() = default;
void InspectorBuilder::MakeEmptyBodyFunction(std::string name, ast::AttributeList attributes) { void InspectorBuilder::MakeEmptyBodyFunction(std::string name,
Func(name, {}, ty.void_(), {Return()}, attributes); utils::VectorRef<const ast::Attribute*> attributes) {
Func(name, utils::Empty, ty.void_(), utils::Vector{Return()}, attributes);
} }
void InspectorBuilder::MakeCallerBodyFunction(std::string caller, void InspectorBuilder::MakeCallerBodyFunction(std::string caller,
std::vector<std::string> callees, utils::VectorRef<std::string> callees,
ast::AttributeList attributes) { utils::VectorRef<const ast::Attribute*> attributes) {
ast::StatementList body; utils::Vector<const ast::Statement*, 8> body;
body.reserve(callees.size() + 1); body.Reserve(callees.Length() + 1);
for (auto callee : callees) { for (auto callee : callees) {
body.push_back(CallStmt(Call(callee))); body.Push(CallStmt(Call(callee)));
} }
body.push_back(Return()); body.Push(Return());
Func(caller, {}, ty.void_(), body, attributes); Func(caller, utils::Empty, ty.void_(), body, attributes);
} }
const ast::Struct* InspectorBuilder::MakeInOutStruct( const ast::Struct* InspectorBuilder::MakeInOutStruct(std::string name,
std::string name, utils::VectorRef<InOutInfo> inout_vars) {
std::vector<std::tuple<std::string, uint32_t>> inout_vars) { utils::Vector<const ast::StructMember*, 8> members;
ast::StructMemberList members;
for (auto var : inout_vars) { for (auto var : inout_vars) {
std::string member_name; std::string member_name;
uint32_t location; uint32_t location;
std::tie(member_name, location) = var; std::tie(member_name, location) = var;
members.push_back(Member(member_name, ty.u32(), {Location(location), Flat()})); members.Push(Member(member_name, ty.u32(),
utils::Vector{
Location(location),
Flat(),
}));
} }
return Structure(name, members); return Structure(name, members);
} }
@ -61,17 +65,15 @@ const ast::Function* InspectorBuilder::MakePlainGlobalReferenceBodyFunction(
std::string func, std::string func,
std::string var, std::string var,
const ast::Type* type, const ast::Type* type,
ast::AttributeList attributes) { utils::VectorRef<const ast::Attribute*> attributes) {
ast::StatementList stmts; utils::Vector<const ast::Statement*, 3> stmts;
stmts.emplace_back(Decl(Var("local_" + var, type))); stmts.Push(Decl(Var("local_" + var, type)));
stmts.emplace_back(Assign("local_" + var, var)); stmts.Push(Assign("local_" + var, var));
stmts.emplace_back(Return()); stmts.Push(Return());
return Func(func, utils::Empty, ty.void_(), std::move(stmts), std::move(attributes));
return Func(func, {}, ty.void_(), stmts, attributes);
} }
bool InspectorBuilder::ContainsName(const std::vector<StageVariable>& vec, bool InspectorBuilder::ContainsName(utils::VectorRef<StageVariable> vec, const std::string& name) {
const std::string& name) {
for (auto& s : vec) { for (auto& s : vec) {
if (s.name == name) { if (s.name == name) {
return true; return true;
@ -84,35 +86,38 @@ std::string InspectorBuilder::StructMemberName(size_t idx, const ast::Type* type
return std::to_string(idx) + type->FriendlyName(Symbols()); return std::to_string(idx) + type->FriendlyName(Symbols());
} }
const ast::Struct* InspectorBuilder::MakeStructType(const std::string& name, const ast::Struct* InspectorBuilder::MakeStructType(
std::vector<const ast::Type*> member_types) { const std::string& name,
ast::StructMemberList members; utils::VectorRef<const ast::Type*> member_types) {
utils::Vector<const ast::StructMember*, 8> members;
for (auto* type : member_types) { for (auto* type : member_types) {
members.push_back(MakeStructMember(members.size(), type, {})); members.Push(MakeStructMember(members.Length(), type, {}));
} }
return MakeStructTypeFromMembers(name, std::move(members)); return MakeStructTypeFromMembers(name, std::move(members));
} }
const ast::Struct* InspectorBuilder::MakeStructTypeFromMembers(const std::string& name, const ast::Struct* InspectorBuilder::MakeStructTypeFromMembers(
ast::StructMemberList members) { const std::string& name,
utils::VectorRef<const ast::StructMember*> members) {
return Structure(name, std::move(members)); return Structure(name, std::move(members));
} }
const ast::StructMember* InspectorBuilder::MakeStructMember(size_t index, const ast::StructMember* InspectorBuilder::MakeStructMember(
const ast::Type* type, size_t index,
ast::AttributeList attributes) { const ast::Type* type,
utils::VectorRef<const ast::Attribute*> attributes) {
return Member(StructMemberName(index, type), type, std::move(attributes)); return Member(StructMemberName(index, type), type, std::move(attributes));
} }
const ast::Struct* InspectorBuilder::MakeUniformBufferType( const ast::Struct* InspectorBuilder::MakeUniformBufferType(
const std::string& name, const std::string& name,
std::vector<const ast::Type*> member_types) { utils::VectorRef<const ast::Type*> member_types) {
return MakeStructType(name, member_types); return MakeStructType(name, member_types);
} }
std::function<const ast::TypeName*()> InspectorBuilder::MakeStorageBufferTypes( std::function<const ast::TypeName*()> InspectorBuilder::MakeStorageBufferTypes(
const std::string& name, const std::string& name,
std::vector<const ast::Type*> member_types) { utils::VectorRef<const ast::Type*> member_types) {
MakeStructType(name, member_types); MakeStructType(name, member_types);
return [this, name] { return ty.type_name(name); }; return [this, name] { return ty.type_name(name); };
} }
@ -122,7 +127,7 @@ void InspectorBuilder::AddUniformBuffer(const std::string& name,
uint32_t group, uint32_t group,
uint32_t binding) { uint32_t binding) {
GlobalVar(name, type, ast::StorageClass::kUniform, GlobalVar(name, type, ast::StorageClass::kUniform,
ast::AttributeList{ utils::Vector{
create<ast::BindingAttribute>(binding), create<ast::BindingAttribute>(binding),
create<ast::GroupAttribute>(group), create<ast::GroupAttribute>(group),
}); });
@ -138,7 +143,7 @@ void InspectorBuilder::AddStorageBuffer(const std::string& name,
uint32_t group, uint32_t group,
uint32_t binding) { uint32_t binding) {
GlobalVar(name, type, ast::StorageClass::kStorage, access, GlobalVar(name, type, ast::StorageClass::kStorage, access,
ast::AttributeList{ utils::Vector{
create<ast::BindingAttribute>(binding), create<ast::BindingAttribute>(binding),
create<ast::GroupAttribute>(group), create<ast::GroupAttribute>(group),
}); });
@ -147,15 +152,15 @@ void InspectorBuilder::AddStorageBuffer(const std::string& name,
void InspectorBuilder::MakeStructVariableReferenceBodyFunction( void InspectorBuilder::MakeStructVariableReferenceBodyFunction(
std::string func_name, std::string func_name,
std::string struct_name, std::string struct_name,
std::vector<std::tuple<size_t, const ast::Type*>> members) { utils::VectorRef<std::tuple<size_t, const ast::Type*>> members) {
ast::StatementList stmts; utils::Vector<const ast::Statement*, 8> stmts;
for (auto member : members) { for (auto member : members) {
size_t member_idx; size_t member_idx;
const ast::Type* member_type; const ast::Type* member_type;
std::tie(member_idx, member_type) = member; std::tie(member_idx, member_type) = member;
std::string member_name = StructMemberName(member_idx, member_type); std::string member_name = StructMemberName(member_idx, member_type);
stmts.emplace_back(Decl(Var("local" + member_name, member_type))); stmts.Push(Decl(Var("local" + member_name, member_type)));
} }
for (auto member : members) { for (auto member : members) {
@ -164,17 +169,17 @@ void InspectorBuilder::MakeStructVariableReferenceBodyFunction(
std::tie(member_idx, member_type) = member; std::tie(member_idx, member_type) = member;
std::string member_name = StructMemberName(member_idx, member_type); std::string member_name = StructMemberName(member_idx, member_type);
stmts.emplace_back(Assign("local" + member_name, MemberAccessor(struct_name, member_name))); stmts.Push(Assign("local" + member_name, MemberAccessor(struct_name, member_name)));
} }
stmts.emplace_back(Return()); stmts.Push(Return());
Func(func_name, {}, ty.void_(), stmts); Func(func_name, utils::Empty, ty.void_(), stmts);
} }
void InspectorBuilder::AddSampler(const std::string& name, uint32_t group, uint32_t binding) { void InspectorBuilder::AddSampler(const std::string& name, uint32_t group, uint32_t binding) {
GlobalVar(name, sampler_type(), GlobalVar(name, sampler_type(),
ast::AttributeList{ utils::Vector{
create<ast::BindingAttribute>(binding), create<ast::BindingAttribute>(binding),
create<ast::GroupAttribute>(group), create<ast::GroupAttribute>(group),
}); });
@ -184,7 +189,7 @@ void InspectorBuilder::AddComparisonSampler(const std::string& name,
uint32_t group, uint32_t group,
uint32_t binding) { uint32_t binding) {
GlobalVar(name, comparison_sampler_type(), GlobalVar(name, comparison_sampler_type(),
ast::AttributeList{ utils::Vector{
create<ast::BindingAttribute>(binding), create<ast::BindingAttribute>(binding),
create<ast::GroupAttribute>(group), create<ast::GroupAttribute>(group),
}); });
@ -195,7 +200,7 @@ void InspectorBuilder::AddResource(const std::string& name,
uint32_t group, uint32_t group,
uint32_t binding) { uint32_t binding) {
GlobalVar(name, type, GlobalVar(name, type,
ast::AttributeList{ utils::Vector{
create<ast::BindingAttribute>(binding), create<ast::BindingAttribute>(binding),
create<ast::GroupAttribute>(group), create<ast::GroupAttribute>(group),
}); });
@ -211,17 +216,15 @@ const ast::Function* InspectorBuilder::MakeSamplerReferenceBodyFunction(
const std::string& sampler_name, const std::string& sampler_name,
const std::string& coords_name, const std::string& coords_name,
const ast::Type* base_type, const ast::Type* base_type,
ast::AttributeList attributes) { utils::VectorRef<const ast::Attribute*> attributes) {
std::string result_name = "sampler_result"; std::string result_name = "sampler_result";
ast::StatementList stmts; utils::Vector stmts{
stmts.emplace_back(Decl(Var(result_name, ty.vec(base_type, 4)))); Decl(Var(result_name, ty.vec(base_type, 4))),
Assign(result_name, Call("textureSample", texture_name, sampler_name, coords_name)),
stmts.emplace_back( Return(),
Assign(result_name, Call("textureSample", texture_name, sampler_name, coords_name))); };
stmts.emplace_back(Return()); return Func(func_name, utils::Empty, ty.void_(), std::move(stmts), std::move(attributes));
return Func(func_name, {}, ty.void_(), stmts, attributes);
} }
const ast::Function* InspectorBuilder::MakeSamplerReferenceBodyFunction( const ast::Function* InspectorBuilder::MakeSamplerReferenceBodyFunction(
@ -231,18 +234,16 @@ const ast::Function* InspectorBuilder::MakeSamplerReferenceBodyFunction(
const std::string& coords_name, const std::string& coords_name,
const std::string& array_index, const std::string& array_index,
const ast::Type* base_type, const ast::Type* base_type,
ast::AttributeList attributes) { utils::VectorRef<const ast::Attribute*> attributes) {
std::string result_name = "sampler_result"; std::string result_name = "sampler_result";
ast::StatementList stmts; utils::Vector stmts{
Decl(Var("sampler_result", ty.vec(base_type, 4))),
stmts.emplace_back(Decl(Var("sampler_result", ty.vec(base_type, 4)))); Assign("sampler_result",
Call("textureSample", texture_name, sampler_name, coords_name, array_index)),
stmts.emplace_back(Assign("sampler_result", Call("textureSample", texture_name, sampler_name, Return(),
coords_name, array_index))); };
stmts.emplace_back(Return()); return Func(func_name, utils::Empty, ty.void_(), std::move(stmts), std::move(attributes));
return Func(func_name, {}, ty.void_(), stmts, attributes);
} }
const ast::Function* InspectorBuilder::MakeComparisonSamplerReferenceBodyFunction( const ast::Function* InspectorBuilder::MakeComparisonSamplerReferenceBodyFunction(
@ -252,17 +253,16 @@ const ast::Function* InspectorBuilder::MakeComparisonSamplerReferenceBodyFunctio
const std::string& coords_name, const std::string& coords_name,
const std::string& depth_name, const std::string& depth_name,
const ast::Type* base_type, const ast::Type* base_type,
ast::AttributeList attributes) { utils::VectorRef<const ast::Attribute*> attributes) {
std::string result_name = "sampler_result"; std::string result_name = "sampler_result";
ast::StatementList stmts; utils::Vector stmts{
Decl(Var("sampler_result", base_type)),
stmts.emplace_back(Decl(Var("sampler_result", base_type))); Assign("sampler_result",
stmts.emplace_back(Assign("sampler_result", Call("textureSampleCompare", texture_name, Call("textureSampleCompare", texture_name, sampler_name, coords_name, depth_name)),
sampler_name, coords_name, depth_name))); Return(),
stmts.emplace_back(Return()); };
return Func(func_name, utils::Empty, ty.void_(), std::move(stmts), std::move(attributes));
return Func(func_name, {}, ty.void_(), stmts, attributes);
} }
const ast::Type* InspectorBuilder::GetBaseType(ResourceBinding::SampledKind sampled_kind) { const ast::Type* InspectorBuilder::GetBaseType(ResourceBinding::SampledKind sampled_kind) {
@ -306,7 +306,7 @@ void InspectorBuilder::AddStorageTexture(const std::string& name,
uint32_t group, uint32_t group,
uint32_t binding) { uint32_t binding) {
GlobalVar(name, type, GlobalVar(name, type,
ast::AttributeList{ utils::Vector{
create<ast::BindingAttribute>(binding), create<ast::BindingAttribute>(binding),
create<ast::GroupAttribute>(group), create<ast::GroupAttribute>(group),
}); });
@ -316,14 +316,14 @@ const ast::Function* InspectorBuilder::MakeStorageTextureBodyFunction(
const std::string& func_name, const std::string& func_name,
const std::string& st_name, const std::string& st_name,
const ast::Type* dim_type, const ast::Type* dim_type,
ast::AttributeList attributes) { utils::VectorRef<const ast::Attribute*> attributes) {
ast::StatementList stmts; utils::Vector stmts{
Decl(Var("dim", dim_type)),
Assign("dim", Call("textureDimensions", st_name)),
Return(),
};
stmts.emplace_back(Decl(Var("dim", dim_type))); return Func(func_name, utils::Empty, ty.void_(), std::move(stmts), std::move(attributes));
stmts.emplace_back(Assign("dim", Call("textureDimensions", st_name)));
stmts.emplace_back(Return());
return Func(func_name, {}, ty.void_(), stmts, attributes);
} }
std::function<const ast::Type*()> InspectorBuilder::GetTypeFunction(ComponentType component, std::function<const ast::Type*()> InspectorBuilder::GetTypeFunction(ComponentType component,

View File

@ -44,28 +44,31 @@ class InspectorBuilder : public ProgramBuilder {
/// Generates an empty function /// Generates an empty function
/// @param name name of the function created /// @param name name of the function created
/// @param attributes the function attributes /// @param attributes the function attributes
void MakeEmptyBodyFunction(std::string name, ast::AttributeList attributes); void MakeEmptyBodyFunction(std::string name,
utils::VectorRef<const ast::Attribute*> attributes);
/// Generates a function that calls other functions /// Generates a function that calls other functions
/// @param caller name of the function created /// @param caller name of the function created
/// @param callees names of the functions to be called /// @param callees names of the functions to be called
/// @param attributes the function attributes /// @param attributes the function attributes
void MakeCallerBodyFunction(std::string caller, void MakeCallerBodyFunction(std::string caller,
std::vector<std::string> callees, utils::VectorRef<std::string> callees,
ast::AttributeList attributes); utils::VectorRef<const ast::Attribute*> attributes);
/// InOutInfo is a tuple of name and location for a structure member
using InOutInfo = std::tuple<std::string, uint32_t>;
/// Generates a struct that contains user-defined IO members /// Generates a struct that contains user-defined IO members
/// @param name the name of the generated struct /// @param name the name of the generated struct
/// @param inout_vars tuples of {name, loc} that will be the struct members /// @param inout_vars tuples of {name, loc} that will be the struct members
/// @returns a structure object /// @returns a structure object
const ast::Struct* MakeInOutStruct(std::string name, const ast::Struct* MakeInOutStruct(std::string name, utils::VectorRef<InOutInfo> inout_vars);
std::vector<std::tuple<std::string, uint32_t>> inout_vars);
// TODO(crbug.com/tint/697): Remove this. // TODO(crbug.com/tint/697): Remove this.
/// Add In/Out variables to the global variables /// Add In/Out variables to the global variables
/// @param inout_vars tuples of {in, out} that will be added as entries to the /// @param inout_vars tuples of {in, out} that will be added as entries to the
/// global variables /// global variables
void AddInOutVariables(std::vector<std::tuple<std::string, std::string>> inout_vars); void AddInOutVariables(utils::VectorRef<std::tuple<std::string, std::string>> inout_vars);
// TODO(crbug.com/tint/697): Remove this. // TODO(crbug.com/tint/697): Remove this.
/// Generates a function that references in/out variables /// Generates a function that references in/out variables
@ -73,9 +76,10 @@ class InspectorBuilder : public ProgramBuilder {
/// @param inout_vars tuples of {in, out} that will be converted into out = in /// @param inout_vars tuples of {in, out} that will be converted into out = in
/// calls in the function body /// calls in the function body
/// @param attributes the function attributes /// @param attributes the function attributes
void MakeInOutVariableBodyFunction(std::string name, void MakeInOutVariableBodyFunction(
std::vector<std::tuple<std::string, std::string>> inout_vars, std::string name,
ast::AttributeList attributes); utils::VectorRef<std::tuple<std::string, std::string>> inout_vars,
utils::VectorRef<const ast::Attribute*> attributes);
// TODO(crbug.com/tint/697): Remove this. // TODO(crbug.com/tint/697): Remove this.
/// Generates a function that references in/out variables and calls another /// Generates a function that references in/out variables and calls another
@ -89,9 +93,8 @@ class InspectorBuilder : public ProgramBuilder {
const ast::Function* MakeInOutVariableCallerBodyFunction( const ast::Function* MakeInOutVariableCallerBodyFunction(
std::string caller, std::string caller,
std::string callee, std::string callee,
std::vector<std::tuple<std::string, std::string>> inout_vars, utils::VectorRef<std::tuple<std::string, std::string>> inout_vars,
ast::AttributeList attributes); utils::VectorRef<const ast::Attribute*> attributes);
/// Generates a function that references module-scoped, plain-typed constant /// Generates a function that references module-scoped, plain-typed constant
/// or variable. /// or variable.
@ -100,15 +103,16 @@ class InspectorBuilder : public ProgramBuilder {
/// @param type type of the const being referenced /// @param type type of the const being referenced
/// @param attributes the function attributes /// @param attributes the function attributes
/// @returns a function object /// @returns a function object
const ast::Function* MakePlainGlobalReferenceBodyFunction(std::string func, const ast::Function* MakePlainGlobalReferenceBodyFunction(
std::string var, std::string func,
const ast::Type* type, std::string var,
ast::AttributeList attributes); const ast::Type* type,
utils::VectorRef<const ast::Attribute*> attributes);
/// @param vec Vector of StageVariable to be searched /// @param vec Vector of StageVariable to be searched
/// @param name Name to be searching for /// @param name Name to be searching for
/// @returns true if name is in vec, otherwise false /// @returns true if name is in vec, otherwise false
bool ContainsName(const std::vector<StageVariable>& vec, const std::string& name); bool ContainsName(utils::VectorRef<StageVariable> vec, const std::string& name);
/// Builds a string for accessing a member in a generated struct /// Builds a string for accessing a member in a generated struct
/// @param idx index of member /// @param idx index of member
@ -121,14 +125,15 @@ class InspectorBuilder : public ProgramBuilder {
/// @param member_types a vector of member types /// @param member_types a vector of member types
/// @returns a struct type /// @returns a struct type
const ast::Struct* MakeStructType(const std::string& name, const ast::Struct* MakeStructType(const std::string& name,
std::vector<const ast::Type*> member_types); utils::VectorRef<const ast::Type*> member_types);
/// Generates a struct type from a list of member nodes. /// Generates a struct type from a list of member nodes.
/// @param name name for the struct type /// @param name name for the struct type
/// @param members a vector of members /// @param members a vector of members
/// @returns a struct type /// @returns a struct type
const ast::Struct* MakeStructTypeFromMembers(const std::string& name, const ast::Struct* MakeStructTypeFromMembers(
ast::StructMemberList members); const std::string& name,
utils::VectorRef<const ast::StructMember*> members);
/// Generates a struct member with a specified index and type. /// Generates a struct member with a specified index and type.
/// @param index index of the field within the struct /// @param index index of the field within the struct
@ -137,14 +142,14 @@ class InspectorBuilder : public ProgramBuilder {
/// @returns a struct member /// @returns a struct member
const ast::StructMember* MakeStructMember(size_t index, const ast::StructMember* MakeStructMember(size_t index,
const ast::Type* type, const ast::Type* type,
ast::AttributeList attributes); utils::VectorRef<const ast::Attribute*> attributes);
/// Generates types appropriate for using in an uniform buffer /// Generates types appropriate for using in an uniform buffer
/// @param name name for the type /// @param name name for the type
/// @param member_types a vector of member types /// @param member_types a vector of member types
/// @returns a struct type that has the layout for an uniform buffer. /// @returns a struct type that has the layout for an uniform buffer.
const ast::Struct* MakeUniformBufferType(const std::string& name, const ast::Struct* MakeUniformBufferType(const std::string& name,
std::vector<const ast::Type*> member_types); utils::VectorRef<const ast::Type*> member_types);
/// Generates types appropriate for using in a storage buffer /// Generates types appropriate for using in a storage buffer
/// @param name name for the type /// @param name name for the type
@ -152,7 +157,7 @@ class InspectorBuilder : public ProgramBuilder {
/// @returns a function that returns the created structure. /// @returns a function that returns the created structure.
std::function<const ast::TypeName*()> MakeStorageBufferTypes( std::function<const ast::TypeName*()> MakeStorageBufferTypes(
const std::string& name, const std::string& name,
std::vector<const ast::Type*> member_types); utils::VectorRef<const ast::Type*> member_types);
/// Adds an uniform buffer variable to the program /// Adds an uniform buffer variable to the program
/// @param name the name of the variable /// @param name the name of the variable
@ -181,14 +186,16 @@ class InspectorBuilder : public ProgramBuilder {
uint32_t group, uint32_t group,
uint32_t binding); uint32_t binding);
/// MemberInfo is a tuple of member index and type.
using MemberInfo = std::tuple<size_t, const ast::Type*>;
/// Generates a function that references a specific struct variable /// Generates a function that references a specific struct variable
/// @param func_name name of the function created /// @param func_name name of the function created
/// @param struct_name name of the struct variabler to be accessed /// @param struct_name name of the struct variabler to be accessed
/// @param members list of members to access, by index and type /// @param members list of members to access, by index and type
void MakeStructVariableReferenceBodyFunction( void MakeStructVariableReferenceBodyFunction(std::string func_name,
std::string func_name, std::string struct_name,
std::string struct_name, utils::VectorRef<MemberInfo> members);
std::vector<std::tuple<size_t, const ast::Type*>> members);
/// Adds a regular sampler variable to the program /// Adds a regular sampler variable to the program
/// @param name the name of the variable /// @param name the name of the variable
@ -225,12 +232,13 @@ class InspectorBuilder : public ProgramBuilder {
/// @param base_type sampler base type /// @param base_type sampler base type
/// @param attributes the function attributes /// @param attributes the function attributes
/// @returns a function that references all of the values specified /// @returns a function that references all of the values specified
const ast::Function* MakeSamplerReferenceBodyFunction(const std::string& func_name, const ast::Function* MakeSamplerReferenceBodyFunction(
const std::string& texture_name, const std::string& func_name,
const std::string& sampler_name, const std::string& texture_name,
const std::string& coords_name, const std::string& sampler_name,
const ast::Type* base_type, const std::string& coords_name,
ast::AttributeList attributes); const ast::Type* base_type,
utils::VectorRef<const ast::Attribute*> attributes);
/// Generates a function that references a specific sampler variable /// Generates a function that references a specific sampler variable
/// @param func_name name of the function created /// @param func_name name of the function created
@ -241,13 +249,14 @@ class InspectorBuilder : public ProgramBuilder {
/// @param base_type sampler base type /// @param base_type sampler base type
/// @param attributes the function attributes /// @param attributes the function attributes
/// @returns a function that references all of the values specified /// @returns a function that references all of the values specified
const ast::Function* MakeSamplerReferenceBodyFunction(const std::string& func_name, const ast::Function* MakeSamplerReferenceBodyFunction(
const std::string& texture_name, const std::string& func_name,
const std::string& sampler_name, const std::string& texture_name,
const std::string& coords_name, const std::string& sampler_name,
const std::string& array_index, const std::string& coords_name,
const ast::Type* base_type, const std::string& array_index,
ast::AttributeList attributes); const ast::Type* base_type,
utils::VectorRef<const ast::Attribute*> attributes);
/// Generates a function that references a specific comparison sampler /// Generates a function that references a specific comparison sampler
/// variable. /// variable.
@ -259,13 +268,14 @@ class InspectorBuilder : public ProgramBuilder {
/// @param base_type sampler base type /// @param base_type sampler base type
/// @param attributes the function attributes /// @param attributes the function attributes
/// @returns a function that references all of the values specified /// @returns a function that references all of the values specified
const ast::Function* MakeComparisonSamplerReferenceBodyFunction(const std::string& func_name, const ast::Function* MakeComparisonSamplerReferenceBodyFunction(
const std::string& texture_name, const std::string& func_name,
const std::string& sampler_name, const std::string& texture_name,
const std::string& coords_name, const std::string& sampler_name,
const std::string& depth_name, const std::string& coords_name,
const ast::Type* base_type, const std::string& depth_name,
ast::AttributeList attributes); const ast::Type* base_type,
utils::VectorRef<const ast::Attribute*> attributes);
/// Gets an appropriate type for the data in a given texture type. /// Gets an appropriate type for the data in a given texture type.
/// @param sampled_kind type of in the texture /// @param sampled_kind type of in the texture
@ -301,10 +311,11 @@ class InspectorBuilder : public ProgramBuilder {
/// @param dim_type type expected by textureDimensons to return /// @param dim_type type expected by textureDimensons to return
/// @param attributes the function attributes /// @param attributes the function attributes
/// @returns a function that references all of the values specified /// @returns a function that references all of the values specified
const ast::Function* MakeStorageTextureBodyFunction(const std::string& func_name, const ast::Function* MakeStorageTextureBodyFunction(
const std::string& st_name, const std::string& func_name,
const ast::Type* dim_type, const std::string& st_name,
ast::AttributeList attributes); const ast::Type* dim_type,
utils::VectorRef<const ast::Attribute*> attributes);
/// Get a generator function that returns a type appropriate for a stage /// Get a generator function that returns a type appropriate for a stage
/// variable with the given combination of component and composition type. /// variable with the given combination of component and composition type.

View File

@ -129,9 +129,9 @@ const ast::Statement* ProgramBuilder::WrapInStatement(const ast::Statement* stmt
return stmt; return stmt;
} }
const ast::Function* ProgramBuilder::WrapInFunction(const ast::StatementList stmts) { const ast::Function* ProgramBuilder::WrapInFunction(utils::VectorRef<const ast::Statement*> stmts) {
return Func("test_function", {}, ty.void_(), std::move(stmts), return Func("test_function", {}, ty.void_(), std::move(stmts),
{ utils::Vector{
create<ast::StageAttribute>(ast::PipelineStage::kCompute), create<ast::StageAttribute>(ast::PipelineStage::kCompute),
WorkgroupSize(1_i, 1_i, 1_i), WorkgroupSize(1_i, 1_i, 1_i),
}); });

View File

@ -120,6 +120,30 @@ class VariableDeclStatement;
namespace tint { namespace tint {
namespace detail {
/// IsVectorLike<T>::value is true if T is a utils::Vector or utils::VectorRef.
template <typename T>
struct IsVectorLike {
/// Non-specialized form of IsVectorLike defaults to false
static constexpr bool value = false;
};
/// IsVectorLike specialization for utils::Vector
template <typename T, size_t N>
struct IsVectorLike<utils::Vector<T, N>> {
/// True for the IsVectorLike specialization of utils::Vector
static constexpr bool value = true;
};
/// IsVectorLike specialization for utils::VectorRef
template <typename T>
struct IsVectorLike<utils::VectorRef<T>> {
/// True for the IsVectorLike specialization of utils::VectorRef
static constexpr bool value = true;
};
} // namespace detail
/// ProgramBuilder is a mutable builder for a Program. /// ProgramBuilder is a mutable builder for a Program.
/// To construct a Program, populate the builder and then `std::move` it to a /// To construct a Program, populate the builder and then `std::move` it to a
/// Program. /// Program.
@ -131,6 +155,12 @@ class ProgramBuilder {
using DisableIfSource = using DisableIfSource =
traits::EnableIfIsNotType<traits::Decay<traits::NthTypeOf<0, TYPES..., void>>, Source>; traits::EnableIfIsNotType<traits::Decay<traits::NthTypeOf<0, TYPES..., void>>, Source>;
/// A helper used to disable overloads if the first type in `TYPES` is a utils::Vector,
/// utils::VectorRef or utils::VectorRef.
template <typename... TYPES>
using DisableIfVectorLike = traits::EnableIf<
!detail::IsVectorLike<traits::Decay<traits::NthTypeOf<0, TYPES..., void>>>::value>;
/// VarOptionals is a helper for accepting a number of optional, extra /// VarOptionals is a helper for accepting a number of optional, extra
/// arguments for Var() and GlobalVar(). /// arguments for Var() and GlobalVar().
struct VarOptionals { struct VarOptionals {
@ -143,13 +173,13 @@ class ProgramBuilder {
ast::StorageClass storage = ast::StorageClass::kNone; ast::StorageClass storage = ast::StorageClass::kNone;
ast::Access access = ast::Access::kUndefined; ast::Access access = ast::Access::kUndefined;
const ast::Expression* constructor = nullptr; const ast::Expression* constructor = nullptr;
ast::AttributeList attributes = {}; utils::Vector<const ast::Attribute*, 4> attributes;
private: private:
void Set(ast::StorageClass sc) { storage = sc; } void Set(ast::StorageClass sc) { storage = sc; }
void Set(ast::Access ac) { access = ac; } void Set(ast::Access ac) { access = ac; }
void Set(const ast::Expression* c) { constructor = c; } void Set(const ast::Expression* c) { constructor = c; }
void Set(const ast::AttributeList& l) { attributes = l; } void Set(utils::VectorRef<const ast::Attribute*> l) { attributes = std::move(l); }
template <typename FIRST, typename... ARGS> template <typename FIRST, typename... ARGS>
void Apply(FIRST&& first, ARGS&&... args) { void Apply(FIRST&& first, ARGS&&... args) {
@ -687,11 +717,12 @@ class ProgramBuilder {
/// @param attrs the optional attributes for the array /// @param attrs the optional attributes for the array
/// @return the tint AST type for a array of size `n` of type `T` /// @return the tint AST type for a array of size `n` of type `T`
template <typename EXPR = ast::Expression*> template <typename EXPR = ast::Expression*>
const ast::Array* array(const ast::Type* subtype, const ast::Array* array(
EXPR&& n = nullptr, const ast::Type* subtype,
ast::AttributeList attrs = {}) const { EXPR&& n = nullptr,
utils::VectorRef<const ast::Attribute*> attrs = utils::Empty) const {
return builder->create<ast::Array>(subtype, builder->Expr(std::forward<EXPR>(n)), return builder->create<ast::Array>(subtype, builder->Expr(std::forward<EXPR>(n)),
attrs); std::move(attrs));
} }
/// @param source the Source of the node /// @param source the Source of the node
@ -700,12 +731,13 @@ class ProgramBuilder {
/// @param attrs the optional attributes for the array /// @param attrs the optional attributes for the array
/// @return the tint AST type for a array of size `n` of type `T` /// @return the tint AST type for a array of size `n` of type `T`
template <typename EXPR = ast::Expression*> template <typename EXPR = ast::Expression*>
const ast::Array* array(const Source& source, const ast::Array* array(
const ast::Type* subtype, const Source& source,
EXPR&& n = nullptr, const ast::Type* subtype,
ast::AttributeList attrs = {}) const { EXPR&& n = nullptr,
return builder->create<ast::Array>(source, subtype, utils::VectorRef<const ast::Attribute*> attrs = utils::Empty) const {
builder->Expr(std::forward<EXPR>(n)), attrs); return builder->create<ast::Array>(
source, subtype, builder->Expr(std::forward<EXPR>(n)), std::move(attrs));
} }
/// @param subtype the array element type /// @param subtype the array element type
@ -714,9 +746,9 @@ class ProgramBuilder {
/// @return the tint AST type for a array of size `n` of type `T` /// @return the tint AST type for a array of size `n` of type `T`
template <typename EXPR> template <typename EXPR>
const ast::Array* array(const ast::Type* subtype, EXPR&& n, uint32_t stride) const { const ast::Array* array(const ast::Type* subtype, EXPR&& n, uint32_t stride) const {
ast::AttributeList attrs; utils::Vector<const ast::Attribute*, 2> attrs;
if (stride) { if (stride) {
attrs.emplace_back(builder->create<ast::StrideAttribute>(stride)); attrs.Push(builder->create<ast::StrideAttribute>(stride));
} }
return array(subtype, std::forward<EXPR>(n), std::move(attrs)); return array(subtype, std::forward<EXPR>(n), std::move(attrs));
} }
@ -731,9 +763,9 @@ class ProgramBuilder {
const ast::Type* subtype, const ast::Type* subtype,
EXPR&& n, EXPR&& n,
uint32_t stride) const { uint32_t stride) const {
ast::AttributeList attrs; utils::Vector<const ast::Attribute*, 2> attrs;
if (stride) { if (stride) {
attrs.emplace_back(builder->create<ast::StrideAttribute>(stride)); attrs.Push(builder->create<ast::StrideAttribute>(stride));
} }
return array(source, subtype, std::forward<EXPR>(n), std::move(attrs)); return array(source, subtype, std::forward<EXPR>(n), std::move(attrs));
} }
@ -1182,9 +1214,9 @@ class ProgramBuilder {
/// `list`. /// `list`.
/// @param list the list to append too /// @param list the list to append too
/// @param arg the arg to create /// @param arg the arg to create
template <typename ARG> template <size_t N, typename ARG>
void Append(ast::ExpressionList& list, ARG&& arg) { void Append(utils::Vector<const ast::Expression*, N>& list, ARG&& arg) {
list.emplace_back(Expr(std::forward<ARG>(arg))); list.Push(Expr(std::forward<ARG>(arg)));
} }
/// Converts `arg0` and `args` to `ast::Expression`s using `Expr()`, /// Converts `arg0` and `args` to `ast::Expression`s using `Expr()`,
@ -1192,29 +1224,38 @@ class ProgramBuilder {
/// @param list the list to append too /// @param list the list to append too
/// @param arg0 the first argument /// @param arg0 the first argument
/// @param args the rest of the arguments /// @param args the rest of the arguments
template <typename ARG0, typename... ARGS> template <size_t N, typename ARG0, typename... ARGS>
void Append(ast::ExpressionList& list, ARG0&& arg0, ARGS&&... args) { void Append(utils::Vector<const ast::Expression*, N>& list, ARG0&& arg0, ARGS&&... args) {
Append(list, std::forward<ARG0>(arg0)); Append(list, std::forward<ARG0>(arg0));
Append(list, std::forward<ARGS>(args)...); Append(list, std::forward<ARGS>(args)...);
} }
/// @return an empty list of expressions /// @return utils::EmptyType
ast::ExpressionList ExprList() { return {}; } utils::EmptyType ExprList() { return utils::Empty; }
/// @param args the list of expressions /// @param args the list of expressions
/// @return the list of expressions converted to `ast::Expression`s using /// @return the list of expressions converted to `ast::Expression`s using
/// `Expr()`, /// `Expr()`,
template <typename... ARGS> template <typename... ARGS, typename = DisableIfVectorLike<ARGS...>>
ast::ExpressionList ExprList(ARGS&&... args) { auto ExprList(ARGS&&... args) {
ast::ExpressionList list; utils::Vector<const ast::Expression*, sizeof...(ARGS)> list;
list.reserve(sizeof...(args));
Append(list, std::forward<ARGS>(args)...); Append(list, std::forward<ARGS>(args)...);
return list; return list;
} }
/// @param list the list of expressions /// @param list the list of expressions
/// @return `list` /// @return `list`
ast::ExpressionList ExprList(ast::ExpressionList list) { return list; } template <typename T, size_t N>
utils::Vector<T, N> ExprList(utils::Vector<T, N>&& list) {
return std::move(list);
}
/// @param list the list of expressions
/// @return `list`
utils::VectorRef<const ast::Expression*> ExprList(
utils::VectorRef<const ast::Expression*> list) {
return list;
}
/// @param args the arguments for the type constructor /// @param args the arguments for the type constructor
/// @return an `ast::CallExpression` of type `ty`, with the values /// @return an `ast::CallExpression` of type `ty`, with the values
@ -1589,7 +1630,7 @@ class ProgramBuilder {
const ast::Const* Const(NAME&& name, const ast::Const* Const(NAME&& name,
const ast::Type* type, const ast::Type* type,
const ast::Expression* constructor, const ast::Expression* constructor,
ast::AttributeList attributes = {}) { utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
return create<ast::Const>(Sym(std::forward<NAME>(name)), type, constructor, attributes); return create<ast::Const>(Sym(std::forward<NAME>(name)), type, constructor, attributes);
} }
@ -1604,7 +1645,7 @@ class ProgramBuilder {
NAME&& name, NAME&& name,
const ast::Type* type, const ast::Type* type,
const ast::Expression* constructor, const ast::Expression* constructor,
ast::AttributeList attributes = {}) { utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
return create<ast::Const>(source, Sym(std::forward<NAME>(name)), type, constructor, return create<ast::Const>(source, Sym(std::forward<NAME>(name)), type, constructor,
attributes); attributes);
} }
@ -1618,7 +1659,7 @@ class ProgramBuilder {
const ast::Let* Let(NAME&& name, const ast::Let* Let(NAME&& name,
const ast::Type* type, const ast::Type* type,
const ast::Expression* constructor, const ast::Expression* constructor,
ast::AttributeList attributes = {}) { utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
return create<ast::Let>(Sym(std::forward<NAME>(name)), type, constructor, attributes); return create<ast::Let>(Sym(std::forward<NAME>(name)), type, constructor, attributes);
} }
@ -1633,7 +1674,7 @@ class ProgramBuilder {
NAME&& name, NAME&& name,
const ast::Type* type, const ast::Type* type,
const ast::Expression* constructor, const ast::Expression* constructor,
ast::AttributeList attributes = {}) { utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
return create<ast::Let>(source, Sym(std::forward<NAME>(name)), type, constructor, return create<ast::Let>(source, Sym(std::forward<NAME>(name)), type, constructor,
attributes); attributes);
} }
@ -1645,7 +1686,7 @@ class ProgramBuilder {
template <typename NAME> template <typename NAME>
const ast::Parameter* Param(NAME&& name, const ast::Parameter* Param(NAME&& name,
const ast::Type* type, const ast::Type* type,
ast::AttributeList attributes = {}) { utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
return create<ast::Parameter>(Sym(std::forward<NAME>(name)), type, attributes); return create<ast::Parameter>(Sym(std::forward<NAME>(name)), type, attributes);
} }
@ -1658,7 +1699,7 @@ class ProgramBuilder {
const ast::Parameter* Param(const Source& source, const ast::Parameter* Param(const Source& source,
NAME&& name, NAME&& name,
const ast::Type* type, const ast::Type* type,
ast::AttributeList attributes = {}) { utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
return create<ast::Parameter>(source, Sym(std::forward<NAME>(name)), type, attributes); return create<ast::Parameter>(source, Sym(std::forward<NAME>(name)), type, attributes);
} }
@ -1712,10 +1753,11 @@ class ProgramBuilder {
/// @returns an `ast::Const` constructed by calling Const() with the arguments of `args`, which /// @returns an `ast::Const` constructed by calling Const() with the arguments of `args`, which
/// is automatically registered as a global variable with the ast::Module. /// is automatically registered as a global variable with the ast::Module.
template <typename NAME> template <typename NAME>
const ast::Const* GlobalConst(NAME&& name, const ast::Const* GlobalConst(
const ast::Type* type, NAME&& name,
const ast::Expression* constructor, const ast::Type* type,
ast::AttributeList attributes = {}) { const ast::Expression* constructor,
utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
auto* var = Const(std::forward<NAME>(name), type, constructor, std::move(attributes)); auto* var = Const(std::forward<NAME>(name), type, constructor, std::move(attributes));
AST().AddGlobalVariable(var); AST().AddGlobalVariable(var);
return var; return var;
@ -1730,11 +1772,12 @@ class ProgramBuilder {
/// arguments of `args`, which is automatically registered as a global /// arguments of `args`, which is automatically registered as a global
/// variable with the ast::Module. /// variable with the ast::Module.
template <typename NAME> template <typename NAME>
const ast::Const* GlobalConst(const Source& source, const ast::Const* GlobalConst(
NAME&& name, const Source& source,
const ast::Type* type, NAME&& name,
const ast::Expression* constructor, const ast::Type* type,
ast::AttributeList attributes = {}) { const ast::Expression* constructor,
utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
auto* var = auto* var =
Const(source, std::forward<NAME>(name), type, constructor, std::move(attributes)); Const(source, std::forward<NAME>(name), type, constructor, std::move(attributes));
AST().AddGlobalVariable(var); AST().AddGlobalVariable(var);
@ -1748,10 +1791,11 @@ class ProgramBuilder {
/// @returns an `ast::Override` which is automatically registered as a global variable with the /// @returns an `ast::Override` which is automatically registered as a global variable with the
/// ast::Module. /// ast::Module.
template <typename NAME> template <typename NAME>
const ast::Override* Override(NAME&& name, const ast::Override* Override(
const ast::Type* type, NAME&& name,
const ast::Expression* constructor, const ast::Type* type,
ast::AttributeList attributes = {}) { const ast::Expression* constructor,
utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
auto* var = create<ast::Override>(source_, Sym(std::forward<NAME>(name)), type, constructor, auto* var = create<ast::Override>(source_, Sym(std::forward<NAME>(name)), type, constructor,
std::move(attributes)); std::move(attributes));
AST().AddGlobalVariable(var); AST().AddGlobalVariable(var);
@ -1766,11 +1810,12 @@ class ProgramBuilder {
/// @returns an `ast::Override` constructed with the arguments of `args`, which is automatically /// @returns an `ast::Override` constructed with the arguments of `args`, which is automatically
/// registered as a global variable with the ast::Module. /// registered as a global variable with the ast::Module.
template <typename NAME> template <typename NAME>
const ast::Override* Override(const Source& source, const ast::Override* Override(
NAME&& name, const Source& source,
const ast::Type* type, NAME&& name,
const ast::Expression* constructor, const ast::Type* type,
ast::AttributeList attributes = {}) { const ast::Expression* constructor,
utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
auto* var = create<ast::Override>(source, Sym(std::forward<NAME>(name)), type, constructor, auto* var = create<ast::Override>(source, Sym(std::forward<NAME>(name)), type, constructor,
std::move(attributes)); std::move(attributes));
AST().AddGlobalVariable(var); AST().AddGlobalVariable(var);
@ -2158,7 +2203,7 @@ class ProgramBuilder {
/// @param group the group index /// @param group the group index
/// @param binding the binding index /// @param binding the binding index
/// @returns a attribute list with both the group and binding attributes /// @returns a attribute list with both the group and binding attributes
ast::AttributeList GroupAndBinding(uint32_t group, uint32_t binding) { utils::Vector<const ast::Attribute*, 2> GroupAndBinding(uint32_t group, uint32_t binding) {
return {Group(group), Binding(binding)}; return {Group(group), Binding(binding)};
} }
@ -2173,16 +2218,18 @@ class ProgramBuilder {
/// attributes /// attributes
/// @returns the function pointer /// @returns the function pointer
template <typename NAME> template <typename NAME>
const ast::Function* Func(const Source& source, const ast::Function* Func(
NAME&& name, const Source& source,
ast::ParameterList params, NAME&& name,
const ast::Type* type, utils::VectorRef<const ast::Parameter*> params,
ast::StatementList body, const ast::Type* type,
ast::AttributeList attributes = {}, utils::VectorRef<const ast::Statement*> body,
ast::AttributeList return_type_attributes = {}) { utils::VectorRef<const ast::Attribute*> attributes = utils::Empty,
auto* func = create<ast::Function>(source, Sym(std::forward<NAME>(name)), params, type, utils::VectorRef<const ast::Attribute*> return_type_attributes = utils::Empty) {
create<ast::BlockStatement>(body), attributes, auto* func =
return_type_attributes); create<ast::Function>(source, Sym(std::forward<NAME>(name)), std::move(params), type,
create<ast::BlockStatement>(std::move(body)),
std::move(attributes), std::move(return_type_attributes));
AST().AddFunction(func); AST().AddFunction(func);
return func; return func;
} }
@ -2197,15 +2244,17 @@ class ProgramBuilder {
/// attributes /// attributes
/// @returns the function pointer /// @returns the function pointer
template <typename NAME> template <typename NAME>
const ast::Function* Func(NAME&& name, const ast::Function* Func(
ast::ParameterList params, NAME&& name,
const ast::Type* type, utils::VectorRef<const ast::Parameter*> params,
ast::StatementList body, const ast::Type* type,
ast::AttributeList attributes = {}, utils::VectorRef<const ast::Statement*> body,
ast::AttributeList return_type_attributes = {}) { utils::VectorRef<const ast::Attribute*> attributes = utils::Empty,
auto* func = create<ast::Function>(Sym(std::forward<NAME>(name)), params, type, utils::VectorRef<const ast::Attribute*> return_type_attributes = utils::Empty) {
create<ast::BlockStatement>(body), attributes, auto* func =
return_type_attributes); create<ast::Function>(Sym(std::forward<NAME>(name)), std::move(params), type,
create<ast::BlockStatement>(std::move(body)),
std::move(attributes), std::move(return_type_attributes));
AST().AddFunction(func); AST().AddFunction(func);
return func; return func;
} }
@ -2300,9 +2349,11 @@ class ProgramBuilder {
/// @param members the struct members /// @param members the struct members
/// @returns the struct type /// @returns the struct type
template <typename NAME> template <typename NAME>
const ast::Struct* Structure(const Source& source, NAME&& name, ast::StructMemberList members) { const ast::Struct* Structure(const Source& source,
NAME&& name,
utils::VectorRef<const ast::StructMember*> members) {
auto sym = Sym(std::forward<NAME>(name)); auto sym = Sym(std::forward<NAME>(name));
auto* type = create<ast::Struct>(source, sym, std::move(members), ast::AttributeList{}); auto* type = create<ast::Struct>(source, sym, std::move(members), utils::Empty);
AST().AddTypeDecl(type); AST().AddTypeDecl(type);
return type; return type;
} }
@ -2312,9 +2363,9 @@ class ProgramBuilder {
/// @param members the struct members /// @param members the struct members
/// @returns the struct type /// @returns the struct type
template <typename NAME> template <typename NAME>
const ast::Struct* Structure(NAME&& name, ast::StructMemberList members) { const ast::Struct* Structure(NAME&& name, utils::VectorRef<const ast::StructMember*> members) {
auto sym = Sym(std::forward<NAME>(name)); auto sym = Sym(std::forward<NAME>(name));
auto* type = create<ast::Struct>(sym, std::move(members), ast::AttributeList{}); auto* type = create<ast::Struct>(sym, std::move(members), utils::Empty);
AST().AddTypeDecl(type); AST().AddTypeDecl(type);
return type; return type;
} }
@ -2326,10 +2377,11 @@ class ProgramBuilder {
/// @param attributes the optional struct member attributes /// @param attributes the optional struct member attributes
/// @returns the struct member pointer /// @returns the struct member pointer
template <typename NAME> template <typename NAME>
const ast::StructMember* Member(const Source& source, const ast::StructMember* Member(
NAME&& name, const Source& source,
const ast::Type* type, NAME&& name,
ast::AttributeList attributes = {}) { const ast::Type* type,
utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
return create<ast::StructMember>(source, Sym(std::forward<NAME>(name)), type, return create<ast::StructMember>(source, Sym(std::forward<NAME>(name)), type,
std::move(attributes)); std::move(attributes));
} }
@ -2340,22 +2392,23 @@ class ProgramBuilder {
/// @param attributes the optional struct member attributes /// @param attributes the optional struct member attributes
/// @returns the struct member pointer /// @returns the struct member pointer
template <typename NAME> template <typename NAME>
const ast::StructMember* Member(NAME&& name, const ast::StructMember* Member(
const ast::Type* type, NAME&& name,
ast::AttributeList attributes = {}) { const ast::Type* type,
utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
return create<ast::StructMember>(source_, Sym(std::forward<NAME>(name)), type, return create<ast::StructMember>(source_, Sym(std::forward<NAME>(name)), type,
std::move(attributes)); std::move(attributes));
} }
/// Creates a ast::StructMember with the given byte offset /// Creates a ast::StructMember with the given byte offset
/// @param offset the offset to use in the StructMemberOffsetattribute /// @param offset the offset to use in the StructMemberOffsetAttribute
/// @param name the struct member name /// @param name the struct member name
/// @param type the struct member type /// @param type the struct member type
/// @returns the struct member pointer /// @returns the struct member pointer
template <typename NAME> template <typename NAME>
const ast::StructMember* Member(uint32_t offset, NAME&& name, const ast::Type* type) { const ast::StructMember* Member(uint32_t offset, NAME&& name, const ast::Type* type) {
return create<ast::StructMember>(source_, Sym(std::forward<NAME>(name)), type, return create<ast::StructMember>(source_, Sym(std::forward<NAME>(name)), type,
ast::AttributeList{ utils::Vector<const ast::Attribute*, 1>{
create<ast::StructMemberOffsetAttribute>(offset), create<ast::StructMemberOffsetAttribute>(offset),
}); });
} }
@ -2367,7 +2420,9 @@ class ProgramBuilder {
template <typename... Statements> template <typename... Statements>
const ast::BlockStatement* Block(const Source& source, Statements&&... statements) { const ast::BlockStatement* Block(const Source& source, Statements&&... statements) {
return create<ast::BlockStatement>( return create<ast::BlockStatement>(
source, ast::StatementList{std::forward<Statements>(statements)...}); source, utils::Vector<const ast::Statement*, sizeof...(statements)>{
std::forward<Statements>(statements)...,
});
} }
/// Creates a ast::BlockStatement with input statements /// Creates a ast::BlockStatement with input statements
@ -2376,7 +2431,9 @@ class ProgramBuilder {
template <typename... STATEMENTS, typename = DisableIfSource<STATEMENTS...>> template <typename... STATEMENTS, typename = DisableIfSource<STATEMENTS...>>
const ast::BlockStatement* Block(STATEMENTS&&... statements) { const ast::BlockStatement* Block(STATEMENTS&&... statements) {
return create<ast::BlockStatement>( return create<ast::BlockStatement>(
ast::StatementList{std::forward<STATEMENTS>(statements)...}); utils::Vector<const ast::Statement*, sizeof...(statements)>{
std::forward<STATEMENTS>(statements)...,
});
} }
/// A wrapper type for the Else statement used to create If statements. /// A wrapper type for the Else statement used to create If statements.
@ -2618,8 +2675,10 @@ class ProgramBuilder {
const ast::SwitchStatement* Switch(const Source& source, const ast::SwitchStatement* Switch(const Source& source,
ExpressionInit&& condition, ExpressionInit&& condition,
Cases&&... cases) { Cases&&... cases) {
return create<ast::SwitchStatement>(source, Expr(std::forward<ExpressionInit>(condition)), return create<ast::SwitchStatement>(
ast::CaseStatementList{std::forward<Cases>(cases)...}); source, Expr(std::forward<ExpressionInit>(condition)),
utils::Vector<const ast::CaseStatement*, sizeof...(cases)>{
std::forward<Cases>(cases)...});
} }
/// Creates a ast::SwitchStatement with input expression and cases /// Creates a ast::SwitchStatement with input expression and cases
@ -2630,8 +2689,10 @@ class ProgramBuilder {
typename... Cases, typename... Cases,
typename = DisableIfSource<ExpressionInit>> typename = DisableIfSource<ExpressionInit>>
const ast::SwitchStatement* Switch(ExpressionInit&& condition, Cases&&... cases) { const ast::SwitchStatement* Switch(ExpressionInit&& condition, Cases&&... cases) {
return create<ast::SwitchStatement>(Expr(std::forward<ExpressionInit>(condition)), return create<ast::SwitchStatement>(
ast::CaseStatementList{std::forward<Cases>(cases)...}); Expr(std::forward<ExpressionInit>(condition)),
utils::Vector<const ast::CaseStatement*, sizeof...(cases)>{
std::forward<Cases>(cases)...});
} }
/// Creates a ast::CaseStatement with input list of selectors, and body /// Creates a ast::CaseStatement with input list of selectors, and body
@ -2640,7 +2701,7 @@ class ProgramBuilder {
/// @param body the case body /// @param body the case body
/// @returns the case statement pointer /// @returns the case statement pointer
const ast::CaseStatement* Case(const Source& source, const ast::CaseStatement* Case(const Source& source,
ast::CaseSelectorList selectors, utils::VectorRef<const ast::IntLiteralExpression*> selectors,
const ast::BlockStatement* body = nullptr) { const ast::BlockStatement* body = nullptr) {
return create<ast::CaseStatement>(source, std::move(selectors), body ? body : Block()); return create<ast::CaseStatement>(source, std::move(selectors), body ? body : Block());
} }
@ -2649,7 +2710,7 @@ class ProgramBuilder {
/// @param selectors list of selectors /// @param selectors list of selectors
/// @param body the case body /// @param body the case body
/// @returns the case statement pointer /// @returns the case statement pointer
const ast::CaseStatement* Case(ast::CaseSelectorList selectors, const ast::CaseStatement* Case(utils::VectorRef<const ast::IntLiteralExpression*> selectors,
const ast::BlockStatement* body = nullptr) { const ast::BlockStatement* body = nullptr) {
return create<ast::CaseStatement>(std::move(selectors), body ? body : Block()); return create<ast::CaseStatement>(std::move(selectors), body ? body : Block());
} }
@ -2660,7 +2721,7 @@ class ProgramBuilder {
/// @returns the case statement pointer /// @returns the case statement pointer
const ast::CaseStatement* Case(const ast::IntLiteralExpression* selector, const ast::CaseStatement* Case(const ast::IntLiteralExpression* selector,
const ast::BlockStatement* body = nullptr) { const ast::BlockStatement* body = nullptr) {
return Case(ast::CaseSelectorList{selector}, body); return Case(utils::Vector{selector}, body);
} }
/// Convenience function that creates a 'default' ast::CaseStatement /// Convenience function that creates a 'default' ast::CaseStatement
@ -2669,14 +2730,14 @@ class ProgramBuilder {
/// @returns the case statement pointer /// @returns the case statement pointer
const ast::CaseStatement* DefaultCase(const Source& source, const ast::CaseStatement* DefaultCase(const Source& source,
const ast::BlockStatement* body = nullptr) { const ast::BlockStatement* body = nullptr) {
return Case(source, ast::CaseSelectorList{}, body); return Case(source, utils::Empty, body);
} }
/// Convenience function that creates a 'default' ast::CaseStatement /// Convenience function that creates a 'default' ast::CaseStatement
/// @param body the case body /// @param body the case body
/// @returns the case statement pointer /// @returns the case statement pointer
const ast::CaseStatement* DefaultCase(const ast::BlockStatement* body = nullptr) { const ast::CaseStatement* DefaultCase(const ast::BlockStatement* body = nullptr) {
return Case(ast::CaseSelectorList{}, body); return Case(utils::Empty, body);
} }
/// Creates an ast::FallthroughStatement /// Creates an ast::FallthroughStatement
@ -2957,13 +3018,15 @@ class ProgramBuilder {
/// @returns the function /// @returns the function
template <typename... ARGS> template <typename... ARGS>
const ast::Function* WrapInFunction(ARGS&&... args) { const ast::Function* WrapInFunction(ARGS&&... args) {
ast::StatementList stmts{WrapInStatement(std::forward<ARGS>(args))...}; utils::Vector stmts{
return WrapInFunction(std::move(stmts)); WrapInStatement(std::forward<ARGS>(args))...,
};
return WrapInFunction(utils::VectorRef<const ast::Statement*>{std::move(stmts)});
} }
/// @param stmts a list of ast::Statement that will be wrapped by a function, /// @param stmts a list of ast::Statement that will be wrapped by a function,
/// so that each statement is reachable by the Resolver. /// so that each statement is reachable by the Resolver.
/// @returns the function /// @returns the function
const ast::Function* WrapInFunction(ast::StatementList stmts); const ast::Function* WrapInFunction(utils::VectorRef<const ast::Statement*> stmts);
/// The builder types /// The builder types
TypesBuilder const ty{this}; TypesBuilder const ty{this};

View File

@ -38,14 +38,14 @@ TEST_F(ProgramBuilderTest, WrapDoesntAffectInner) {
return builder; return builder;
}()); }());
ASSERT_EQ(inner.AST().Functions().size(), 1u); ASSERT_EQ(inner.AST().Functions().Length(), 1u);
ASSERT_TRUE(inner.Symbols().Get("a").IsValid()); ASSERT_TRUE(inner.Symbols().Get("a").IsValid());
ASSERT_FALSE(inner.Symbols().Get("b").IsValid()); ASSERT_FALSE(inner.Symbols().Get("b").IsValid());
ProgramBuilder outer = ProgramBuilder::Wrap(&inner); ProgramBuilder outer = ProgramBuilder::Wrap(&inner);
ASSERT_EQ(inner.AST().Functions().size(), 1u); ASSERT_EQ(inner.AST().Functions().Length(), 1u);
ASSERT_EQ(outer.AST().Functions().size(), 1u); ASSERT_EQ(outer.AST().Functions().Length(), 1u);
EXPECT_EQ(inner.AST().Functions()[0], outer.AST().Functions()[0]); EXPECT_EQ(inner.AST().Functions()[0], outer.AST().Functions()[0]);
EXPECT_TRUE(inner.Symbols().Get("a").IsValid()); EXPECT_TRUE(inner.Symbols().Get("a").IsValid());
EXPECT_EQ(inner.Symbols().Get("a"), outer.Symbols().Get("a")); EXPECT_EQ(inner.Symbols().Get("a"), outer.Symbols().Get("a"));
@ -57,8 +57,8 @@ TEST_F(ProgramBuilderTest, WrapDoesntAffectInner) {
auto* ty = outer.ty.f32(); auto* ty = outer.ty.f32();
outer.Func("b", {}, ty, {}, {}); outer.Func("b", {}, ty, {}, {});
ASSERT_EQ(inner.AST().Functions().size(), 1u); ASSERT_EQ(inner.AST().Functions().Length(), 1u);
ASSERT_EQ(outer.AST().Functions().size(), 2u); ASSERT_EQ(outer.AST().Functions().Length(), 2u);
EXPECT_EQ(inner.AST().Functions()[0], outer.AST().Functions()[0]); EXPECT_EQ(inner.AST().Functions()[0], outer.AST().Functions()[0]);
EXPECT_EQ(outer.AST().Functions()[1]->symbol, outer.Symbols().Get("b")); EXPECT_EQ(outer.AST().Functions()[1]->symbol, outer.Symbols().Get("b"));
EXPECT_EQ(inner.Symbols().Get("a"), outer.Symbols().Get("a")); EXPECT_EQ(inner.Symbols().Get("a"), outer.Symbols().Get("a"));

View File

@ -28,7 +28,7 @@ TEST_F(ProgramTest, Unbuilt) {
TEST_F(ProgramTest, Creation) { TEST_F(ProgramTest, Creation) {
Program program(std::move(*this)); Program program(std::move(*this));
EXPECT_EQ(program.AST().Functions().size(), 0u); EXPECT_EQ(program.AST().Functions().Length(), 0u);
} }
TEST_F(ProgramTest, EmptyIsValid) { TEST_F(ProgramTest, EmptyIsValid) {

View File

@ -18,7 +18,8 @@
#include <memory> #include <memory>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <vector>
#include "src/tint/utils/vector.h"
namespace tint::reader::spirv { namespace tint::reader::spirv {
@ -146,7 +147,7 @@ struct Construct {
}; };
/// ConstructList is a list of Construct unique pointers. /// ConstructList is a list of Construct unique pointers.
using ConstructList = std::vector<std::unique_ptr<Construct>>; using ConstructList = utils::Vector<std::unique_ptr<Construct>, 8>;
/// Converts a construct kind to a string. /// Converts a construct kind to a string.
/// @param kind the construct kind to convert /// @param kind the construct kind to convert

File diff suppressed because it is too large Load Diff

View File

@ -16,6 +16,7 @@
#define SRC_TINT_READER_SPIRV_FUNCTION_H_ #define SRC_TINT_READER_SPIRV_FUNCTION_H_
#include <memory> #include <memory>
#include <optional>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
@ -125,7 +126,7 @@ struct BlockInfo {
/// switch? /// switch?
bool default_is_merge = false; bool default_is_merge = false;
/// The list of switch values that cause a branch to this block. /// The list of switch values that cause a branch to this block.
std::unique_ptr<std::vector<uint64_t>> case_values; std::optional<utils::Vector<uint64_t, 4>> case_values;
/// The following fields record relationships among blocks in a selection /// The following fields record relationships among blocks in a selection
/// construct for an OpBranchConditional instruction. /// construct for an OpBranchConditional instruction.
@ -158,7 +159,7 @@ struct BlockInfo {
/// The result IDs that this block is responsible for declaring as a /// The result IDs that this block is responsible for declaring as a
/// hoisted variable. /// hoisted variable.
/// @see DefInfo#requires_hoisted_def /// @see DefInfo#requires_hoisted_def
std::vector<uint32_t> hoisted_ids; utils::Vector<uint32_t, 4> hoisted_ids;
/// A PhiAssignment represents the assignment of a value to the state /// A PhiAssignment represents the assignment of a value to the state
/// variable associated with an OpPhi in a successor block. /// variable associated with an OpPhi in a successor block.
@ -170,10 +171,10 @@ struct BlockInfo {
}; };
/// If this basic block branches to a visited basic block containing phis, /// If this basic block branches to a visited basic block containing phis,
/// then this is the list of writes to the variables associated those phis. /// then this is the list of writes to the variables associated those phis.
std::vector<PhiAssignment> phi_assignments; utils::Vector<PhiAssignment, 4> phi_assignments;
/// The IDs of OpPhi instructions which require their associated state /// The IDs of OpPhi instructions which require their associated state
/// variable to be declared in this basic block. /// variable to be declared in this basic block.
std::vector<uint32_t> phis_needing_state_vars; utils::Vector<uint32_t, 4> phis_needing_state_vars;
}; };
/// Writes the BlockInfo to the ostream /// Writes the BlockInfo to the ostream
@ -388,6 +389,12 @@ class StatementBuilder : public Castable<StatementBuilder, ast::Statement> {
/// A FunctionEmitter emits a SPIR-V function onto a Tint AST module. /// A FunctionEmitter emits a SPIR-V function onto a Tint AST module.
class FunctionEmitter { class FunctionEmitter {
using AttributeList = utils::Vector<const ast::Attribute*, 8>;
using StructMemberList = utils::Vector<const ast::StructMember*, 8>;
using ExpressionList = utils::Vector<const ast::Expression*, 8>;
using ParameterList = utils::Vector<const ast::Parameter*, 8>;
using StatementList = utils::Vector<const ast::Statement*, 8>;
public: public:
/// Creates a FunctionEmitter, and prepares to write to the AST module /// Creates a FunctionEmitter, and prepares to write to the AST module
/// in `pi` /// in `pi`
@ -420,7 +427,7 @@ class FunctionEmitter {
/// Finalizes any StatementBuilders returns the body of the function. /// Finalizes any StatementBuilders returns the body of the function.
/// Must only be called once, and to be used only for testing. /// Must only be called once, and to be used only for testing.
/// @returns the body of the function. /// @returns the body of the function.
const ast::StatementList ast_body(); StatementList ast_body();
/// Records failure. /// Records failure.
/// @returns a FailStream on which to emit diagnostics. /// @returns a FailStream on which to emit diagnostics.
@ -455,12 +462,12 @@ class FunctionEmitter {
/// @returns false if emission failed /// @returns false if emission failed
bool EmitPipelineInput(std::string var_name, bool EmitPipelineInput(std::string var_name,
const Type* var_type, const Type* var_type,
ast::AttributeList* decos, AttributeList* decos,
std::vector<int> index_prefix, utils::Vector<int, 8> index_prefix,
const Type* tip_type, const Type* tip_type,
const Type* forced_param_type, const Type* forced_param_type,
ast::ParameterList* params, ParameterList* params,
ast::StatementList* statements); StatementList* statements);
/// Creates one or more struct members from an output variable, and the /// Creates one or more struct members from an output variable, and the
/// expressions that compute the value they contribute to the entry point /// expressions that compute the value they contribute to the entry point
@ -471,37 +478,30 @@ class FunctionEmitter {
/// @param var_name The name of the variable /// @param var_name The name of the variable
/// @param var_type The store type of the variable /// @param var_type The store type of the variable
/// @param decos The variable's decorations /// @param decos The variable's decorations
/// @param index_prefix Indices stepping into the variable, indicating /// @param index_prefix Indices stepping into the variable, indicating what part of the variable
/// what part of the variable to populate. /// to populate.
/// @param tip_type The type of the component inside variable, after indexing /// @param tip_type The type of the component inside variable, after indexing with the indices
/// with the indices in `index_prefix`. /// in `index_prefix`.
/// @param forced_member_type The type forced by WGSL, if the variable is a /// @param forced_member_type The type forced by WGSL, if the variable is a builtin, otherwise
/// builtin, otherwise the same as var_type. /// the same as var_type.
/// @param return_members The struct member list where the new member is /// @param return_members The struct member list where the new member is added.
/// added. /// @param return_exprs The expression list where the return expression is added.
/// @param return_exprs The expression list where the return expression is
/// added.
/// @returns false if emission failed /// @returns false if emission failed
bool EmitPipelineOutput(std::string var_name, bool EmitPipelineOutput(std::string var_name,
const Type* var_type, const Type* var_type,
ast::AttributeList* decos, AttributeList* decos,
std::vector<int> index_prefix, utils::Vector<int, 8> index_prefix,
const Type* tip_type, const Type* tip_type,
const Type* forced_member_type, const Type* forced_member_type,
ast::StructMemberList* return_members, StructMemberList* return_members,
ast::ExpressionList* return_exprs); ExpressionList* return_exprs);
/// Updates the attribute list, replacing an existing Location attribute /// Updates the attribute list, replacing an existing Location attribute
/// with another having one higher location value. Does nothing if no /// with another having one higher location value. Does nothing if no
/// location attribute exists. /// location attribute exists.
/// Assumes the list contains at most one Location attribute. /// Assumes the list contains at most one Location attribute.
/// @param attributes the attribute list to modify /// @param attributes the attribute list to modify
void IncrementLocation(ast::AttributeList* attributes); void IncrementLocation(AttributeList* attributes);
/// Returns the Location attribute, if it exists.
/// @param attributes the list of attributes to search
/// @returns the Location attribute, or nullptr if it doesn't exist
const ast::Attribute* GetLocation(const ast::AttributeList& attributes);
/// Create an ast::BlockStatement representing the body of the function. /// Create an ast::BlockStatement representing the body of the function.
/// This creates the statement stack, which is non-empty for the lifetime /// This creates the statement stack, which is non-empty for the lifetime
@ -913,7 +913,7 @@ class FunctionEmitter {
/// On failure, issues an error and returns an empty expression list. /// On failure, issues an error and returns an empty expression list.
/// @param image_access the image access instruction /// @param image_access the image access instruction
/// @returns an ExpressionList of the coordinate and array index (if any) /// @returns an ExpressionList of the coordinate and array index (if any)
ast::ExpressionList MakeCoordinateOperandsForImageAccess( ExpressionList MakeCoordinateOperandsForImageAccess(
const spvtools::opt::Instruction& image_access); const spvtools::opt::Instruction& image_access);
/// Returns the given value as an I32. If it's already an I32 then this /// Returns the given value as an I32. If it's already an I32 then this
@ -951,11 +951,11 @@ class FunctionEmitter {
/// Function name /// Function name
std::string name; std::string name;
/// Function parameters /// Function parameters
ast::ParameterList params; ParameterList params;
/// Function return type /// Function return type
const Type* return_type; const Type* return_type;
/// Function attributes /// Function attributes
ast::AttributeList attributes; AttributeList attributes;
}; };
/// Parse the function declaration, which comprises the name, parameters, and /// Parse the function declaration, which comprises the name, parameters, and
@ -1117,8 +1117,8 @@ class FunctionEmitter {
/// @return the built StatementBuilder /// @return the built StatementBuilder
template <typename T, typename... ARGS> template <typename T, typename... ARGS>
T* AddStatementBuilder(ARGS&&... args) { T* AddStatementBuilder(ARGS&&... args) {
TINT_ASSERT(Reader, !statements_stack_.empty()); TINT_ASSERT(Reader, !statements_stack_.IsEmpty());
return statements_stack_.back().AddStatementBuilder<T>(std::forward<ARGS>(args)...); return statements_stack_.Back().AddStatementBuilder<T>(std::forward<ARGS>(args)...);
} }
/// Returns the source record for the given instruction. /// Returns the source record for the given instruction.
@ -1126,10 +1126,10 @@ class FunctionEmitter {
/// @return the Source record, or a default one /// @return the Source record, or a default one
Source GetSourceForInst(const spvtools::opt::Instruction& inst) const; Source GetSourceForInst(const spvtools::opt::Instruction& inst) const;
/// @returns the last statetment in the top of the statement stack. /// @returns the last statement in the top of the statement stack.
const ast::Statement* LastStatement(); const ast::Statement* LastStatement();
using CompletionAction = std::function<void(const ast::StatementList&)>; using CompletionAction = std::function<void(const StatementList&)>;
// A StatementBlock represents a braced-list of statements while it is being // A StatementBlock represents a braced-list of statements while it is being
// constructed. // constructed.
@ -1181,7 +1181,7 @@ class FunctionEmitter {
/// @return the list of statements being built, if this construct is not a /// @return the list of statements being built, if this construct is not a
/// switch. /// switch.
const ast::StatementList& GetStatements() const { return statements_; } const StatementList& GetStatements() const { return statements_; }
private: private:
/// The construct to which this construct constributes. /// The construct to which this construct constributes.
@ -1193,7 +1193,7 @@ class FunctionEmitter {
/// The completion action finishes processing this statement block. /// The completion action finishes processing this statement block.
FunctionEmitter::CompletionAction const completion_action_; FunctionEmitter::CompletionAction const completion_action_;
/// The list of statements being built, if this construct is not a switch. /// The list of statements being built, if this construct is not a switch.
ast::StatementList statements_; StatementList statements_;
/// Owned statement builders /// Owned statement builders
std::vector<std::unique_ptr<StatementBuilder>> builders_; std::vector<std::unique_ptr<StatementBuilder>> builders_;
@ -1251,7 +1251,6 @@ class FunctionEmitter {
return builder_.create<T>(std::forward<ARGS>(args)...); return builder_.create<T>(std::forward<ARGS>(args)...);
} }
using StatementsStack = std::vector<StatementBlock>;
using PtrAs = ParserImpl::PtrAs; using PtrAs = ParserImpl::PtrAs;
ParserImpl& parser_impl_; ParserImpl& parser_impl_;
@ -1275,7 +1274,7 @@ class FunctionEmitter {
// for the entire function. This stack is never empty. // for the entire function. This stack is never empty.
// The `construct` member for the 0th element is only valid during the // The `construct` member for the 0th element is only valid during the
// lifetime of the EmitFunctionBodyStatements method. // lifetime of the EmitFunctionBodyStatements method.
StatementsStack statements_stack_; utils::Vector<StatementBlock, 8> statements_stack_;
// The map of IDs that have already had an identifier name generated for it, // The map of IDs that have already had an identifier name generated for it,
// to their Type. // to their Type.

View File

@ -87,13 +87,13 @@ TEST_F(SpvParserTest, EmitStatement_ScalarCallNoParams) {
OpFunctionEnd OpFunctionEnd
)")); )"));
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error(); ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
ast::StatementList f100; utils::Vector<const ast::Statement*, 4> f100;
{ {
auto fe = p->function_emitter(100); auto fe = p->function_emitter(100);
EXPECT_TRUE(fe.EmitBody()) << p->error(); EXPECT_TRUE(fe.EmitBody()) << p->error();
f100 = fe.ast_body(); f100 = fe.ast_body();
} }
ast::StatementList f50; utils::Vector<const ast::Statement*, 4> f50;
{ {
auto fe = p->function_emitter(50); auto fe = p->function_emitter(50);
EXPECT_TRUE(fe.EmitBody()) << p->error(); EXPECT_TRUE(fe.EmitBody()) << p->error();
@ -128,13 +128,13 @@ TEST_F(SpvParserTest, EmitStatement_ScalarCallNoParamsUsedTwice) {
OpFunctionEnd OpFunctionEnd
)")); )"));
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error(); ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
ast::StatementList f100; utils::Vector<const ast::Statement*, 4> f100;
{ {
auto fe = p->function_emitter(100); auto fe = p->function_emitter(100);
EXPECT_TRUE(fe.EmitBody()) << p->error(); EXPECT_TRUE(fe.EmitBody()) << p->error();
f100 = fe.ast_body(); f100 = fe.ast_body();
} }
ast::StatementList f50; utils::Vector<const ast::Statement*, 4> f50;
{ {
auto fe = p->function_emitter(50); auto fe = p->function_emitter(50);
EXPECT_TRUE(fe.EmitBody()) << p->error(); EXPECT_TRUE(fe.EmitBody()) << p->error();

View File

@ -2894,8 +2894,8 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_OuterConstructIsFunction_Sin
fe.ComputeBlockOrderAndPositions(); fe.ComputeBlockOrderAndPositions();
fe.RegisterMerges(); fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs()); EXPECT_TRUE(fe.LabelControlFlowConstructs());
EXPECT_EQ(fe.constructs().size(), 1u); EXPECT_EQ(fe.constructs().Length(), 1u);
auto& c = fe.constructs().front(); auto& c = fe.constructs().Front();
EXPECT_THAT(ToString(c), Eq("Construct{ Function [0,1) begin_id:10 end_id:0 " EXPECT_THAT(ToString(c), Eq("Construct{ Function [0,1) begin_id:10 end_id:0 "
"depth:0 parent:null }")); "depth:0 parent:null }"));
EXPECT_EQ(fe.GetBlockInfo(10)->construct, c.get()); EXPECT_EQ(fe.GetBlockInfo(10)->construct, c.get());
@ -2920,8 +2920,8 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_OuterConstructIsFunction_Mul
fe.ComputeBlockOrderAndPositions(); fe.ComputeBlockOrderAndPositions();
fe.RegisterMerges(); fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs()); EXPECT_TRUE(fe.LabelControlFlowConstructs());
EXPECT_EQ(fe.constructs().size(), 1u); EXPECT_EQ(fe.constructs().Length(), 1u);
auto& c = fe.constructs().front(); auto& c = fe.constructs().Front();
EXPECT_THAT(ToString(c), Eq("Construct{ Function [0,2) begin_id:10 end_id:0 " EXPECT_THAT(ToString(c), Eq("Construct{ Function [0,2) begin_id:10 end_id:0 "
"depth:0 parent:null }")); "depth:0 parent:null }"));
EXPECT_EQ(fe.GetBlockInfo(10)->construct, c.get()); EXPECT_EQ(fe.GetBlockInfo(10)->construct, c.get());
@ -2955,7 +2955,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_FunctionIsOnlyIfSelectionAnd
fe.RegisterMerges(); fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs()); EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs(); const auto& constructs = fe.constructs();
EXPECT_EQ(constructs.size(), 2u); EXPECT_EQ(constructs.Length(), 2u);
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{ EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
Construct{ Function [0,4) begin_id:10 end_id:0 depth:0 parent:null } Construct{ Function [0,4) begin_id:10 end_id:0 depth:0 parent:null }
Construct{ IfSelection [0,3) begin_id:10 end_id:99 depth:1 parent:Function@10 } Construct{ IfSelection [0,3) begin_id:10 end_id:99 depth:1 parent:Function@10 }
@ -3001,7 +3001,7 @@ TEST_F(SpvParserCFGTest,
fe.RegisterMerges(); fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs()); EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs(); const auto& constructs = fe.constructs();
EXPECT_EQ(constructs.size(), 2u); EXPECT_EQ(constructs.Length(), 2u);
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{ EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
Construct{ Function [0,6) begin_id:5 end_id:0 depth:0 parent:null } Construct{ Function [0,6) begin_id:5 end_id:0 depth:0 parent:null }
Construct{ IfSelection [1,4) begin_id:10 end_id:99 depth:1 parent:Function@5 } Construct{ IfSelection [1,4) begin_id:10 end_id:99 depth:1 parent:Function@5 }
@ -3045,7 +3045,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_SwitchSelection) {
fe.RegisterMerges(); fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs()); EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs(); const auto& constructs = fe.constructs();
EXPECT_EQ(constructs.size(), 2u); EXPECT_EQ(constructs.Length(), 2u);
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{ EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
Construct{ Function [0,5) begin_id:10 end_id:0 depth:0 parent:null } Construct{ Function [0,5) begin_id:10 end_id:0 depth:0 parent:null }
Construct{ SwitchSelection [0,4) begin_id:10 end_id:99 depth:1 parent:Function@10 in-c-l-s:SwitchSelection@10 } Construct{ SwitchSelection [0,4) begin_id:10 end_id:99 depth:1 parent:Function@10 in-c-l-s:SwitchSelection@10 }
@ -3082,7 +3082,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_SingleBlockLoop) {
fe.RegisterMerges(); fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs()); EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs(); const auto& constructs = fe.constructs();
EXPECT_EQ(constructs.size(), 2u); EXPECT_EQ(constructs.Length(), 2u);
// A single-block loop consists *only* of a continue target with one block in // A single-block loop consists *only* of a continue target with one block in
// it. // it.
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{ EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
@ -3223,7 +3223,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_MergeBlockIsAlsoSingleBlockL
fe.RegisterMerges(); fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs()); EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs(); const auto& constructs = fe.constructs();
EXPECT_EQ(constructs.size(), 3u); EXPECT_EQ(constructs.Length(), 3u);
// A single-block loop consists *only* of a continue target with one block in // A single-block loop consists *only* of a continue target with one block in
// it. // it.
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{ EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
@ -3271,7 +3271,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_MergeBlockIsAlsoMultiBlockLo
fe.RegisterMerges(); fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs()); EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs(); const auto& constructs = fe.constructs();
EXPECT_EQ(constructs.size(), 4u); EXPECT_EQ(constructs.Length(), 4u);
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{ EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
Construct{ Function [0,5) begin_id:10 end_id:0 depth:0 parent:null } Construct{ Function [0,5) begin_id:10 end_id:0 depth:0 parent:null }
Construct{ IfSelection [0,2) begin_id:10 end_id:50 depth:1 parent:Function@10 } Construct{ IfSelection [0,2) begin_id:10 end_id:50 depth:1 parent:Function@10 }
@ -3330,7 +3330,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_If_If) {
fe.RegisterMerges(); fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs()); EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs(); const auto& constructs = fe.constructs();
EXPECT_EQ(constructs.size(), 4u); EXPECT_EQ(constructs.Length(), 4u);
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{ EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
Construct{ Function [0,9) begin_id:10 end_id:0 depth:0 parent:null } Construct{ Function [0,9) begin_id:10 end_id:0 depth:0 parent:null }
Construct{ IfSelection [0,8) begin_id:10 end_id:99 depth:1 parent:Function@10 } Construct{ IfSelection [0,8) begin_id:10 end_id:99 depth:1 parent:Function@10 }
@ -3390,7 +3390,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_Switch_If) {
fe.RegisterMerges(); fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs()); EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs(); const auto& constructs = fe.constructs();
EXPECT_EQ(constructs.size(), 4u); EXPECT_EQ(constructs.Length(), 4u);
// The ordering among siblings depends on the computed block order. // The ordering among siblings depends on the computed block order.
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{ EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
Construct{ Function [0,8) begin_id:10 end_id:0 depth:0 parent:null } Construct{ Function [0,8) begin_id:10 end_id:0 depth:0 parent:null }
@ -3440,7 +3440,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_If_Switch) {
fe.RegisterMerges(); fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs()); EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs(); const auto& constructs = fe.constructs();
EXPECT_EQ(constructs.size(), 3u); EXPECT_EQ(constructs.Length(), 3u);
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{ EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
Construct{ Function [0,5) begin_id:10 end_id:0 depth:0 parent:null } Construct{ Function [0,5) begin_id:10 end_id:0 depth:0 parent:null }
Construct{ IfSelection [0,4) begin_id:10 end_id:99 depth:1 parent:Function@10 } Construct{ IfSelection [0,4) begin_id:10 end_id:99 depth:1 parent:Function@10 }
@ -3494,7 +3494,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_Loop_Loop) {
fe.RegisterMerges(); fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs()); EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs(); const auto& constructs = fe.constructs();
EXPECT_EQ(constructs.size(), 4u); EXPECT_EQ(constructs.Length(), 4u);
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{ EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
Construct{ Function [0,8) begin_id:10 end_id:0 depth:0 parent:null } Construct{ Function [0,8) begin_id:10 end_id:0 depth:0 parent:null }
Construct{ Continue [4,6) begin_id:50 end_id:89 depth:1 parent:Function@10 in-c:Continue@50 } Construct{ Continue [4,6) begin_id:50 end_id:89 depth:1 parent:Function@10 in-c:Continue@50 }
@ -3549,7 +3549,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_Loop_If) {
fe.RegisterMerges(); fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs()); EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs(); const auto& constructs = fe.constructs();
EXPECT_EQ(constructs.size(), 4u); EXPECT_EQ(constructs.Length(), 4u);
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{ EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
Construct{ Function [0,7) begin_id:10 end_id:0 depth:0 parent:null } Construct{ Function [0,7) begin_id:10 end_id:0 depth:0 parent:null }
Construct{ Continue [5,6) begin_id:80 end_id:99 depth:1 parent:Function@10 in-c:Continue@80 } Construct{ Continue [5,6) begin_id:80 end_id:99 depth:1 parent:Function@10 in-c:Continue@80 }
@ -3600,7 +3600,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_LoopContinue_If) {
fe.RegisterMerges(); fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs()); EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs(); const auto& constructs = fe.constructs();
EXPECT_EQ(constructs.size(), 4u); EXPECT_EQ(constructs.Length(), 4u);
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{ EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
Construct{ Function [0,6) begin_id:10 end_id:0 depth:0 parent:null } Construct{ Function [0,6) begin_id:10 end_id:0 depth:0 parent:null }
Construct{ Continue [2,5) begin_id:30 end_id:99 depth:1 parent:Function@10 in-c:Continue@30 } Construct{ Continue [2,5) begin_id:30 end_id:99 depth:1 parent:Function@10 in-c:Continue@30 }
@ -3644,7 +3644,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_If_SingleBlockLoop) {
fe.RegisterMerges(); fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs()); EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs(); const auto& constructs = fe.constructs();
EXPECT_EQ(constructs.size(), 3u); EXPECT_EQ(constructs.Length(), 3u);
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{ EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
Construct{ Function [0,4) begin_id:10 end_id:0 depth:0 parent:null } Construct{ Function [0,4) begin_id:10 end_id:0 depth:0 parent:null }
Construct{ IfSelection [0,3) begin_id:10 end_id:99 depth:1 parent:Function@10 } Construct{ IfSelection [0,3) begin_id:10 end_id:99 depth:1 parent:Function@10 }
@ -3693,7 +3693,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_If_MultiBlockLoop) {
fe.RegisterMerges(); fe.RegisterMerges();
EXPECT_TRUE(fe.LabelControlFlowConstructs()); EXPECT_TRUE(fe.LabelControlFlowConstructs());
const auto& constructs = fe.constructs(); const auto& constructs = fe.constructs();
EXPECT_EQ(constructs.size(), 4u); EXPECT_EQ(constructs.Length(), 4u);
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{ EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
Construct{ Function [0,7) begin_id:10 end_id:0 depth:0 parent:null } Construct{ Function [0,7) begin_id:10 end_id:0 depth:0 parent:null }
Construct{ IfSelection [0,6) begin_id:10 end_id:99 depth:1 parent:Function@10 } Construct{ IfSelection [0,6) begin_id:10 end_id:99 depth:1 parent:Function@10 }
@ -3743,7 +3743,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_LoopInterallyDiverge) {
auto fe = p->function_emitter(100); auto fe = p->function_emitter(100);
ASSERT_TRUE(FlowLabelControlFlowConstructs(&fe)) << p->error(); ASSERT_TRUE(FlowLabelControlFlowConstructs(&fe)) << p->error();
const auto& constructs = fe.constructs(); const auto& constructs = fe.constructs();
EXPECT_EQ(constructs.size(), 4u); EXPECT_EQ(constructs.Length(), 4u);
ASSERT_THAT(ToString(constructs), Eq(R"(ConstructList{ ASSERT_THAT(ToString(constructs), Eq(R"(ConstructList{
Construct{ Function [0,6) begin_id:10 end_id:0 depth:0 parent:null } Construct{ Function [0,6) begin_id:10 end_id:0 depth:0 parent:null }
Construct{ Continue [4,5) begin_id:90 end_id:99 depth:1 parent:Function@10 in-c:Continue@90 } Construct{ Continue [4,5) begin_id:90 end_id:99 depth:1 parent:Function@10 in-c:Continue@90 }
@ -4157,7 +4157,7 @@ TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_NoSwitch) {
EXPECT_EQ(bi10->case_head_for, nullptr); EXPECT_EQ(bi10->case_head_for, nullptr);
EXPECT_EQ(bi10->default_head_for, nullptr); EXPECT_EQ(bi10->default_head_for, nullptr);
EXPECT_FALSE(bi10->default_is_merge); EXPECT_FALSE(bi10->default_is_merge);
EXPECT_EQ(bi10->case_values.get(), nullptr); EXPECT_FALSE(bi10->case_values.has_value());
} }
TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_DefaultIsMerge) { TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_DefaultIsMerge) {
@ -4192,7 +4192,7 @@ TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_DefaultIsMerge) {
ASSERT_NE(bi99->default_head_for, nullptr); ASSERT_NE(bi99->default_head_for, nullptr);
EXPECT_EQ(bi99->default_head_for->begin_id, 10u); EXPECT_EQ(bi99->default_head_for->begin_id, 10u);
EXPECT_TRUE(bi99->default_is_merge); EXPECT_TRUE(bi99->default_is_merge);
EXPECT_EQ(bi99->case_values.get(), nullptr); EXPECT_FALSE(bi99->case_values.has_value());
} }
TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_DefaultIsNotMerge) { TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_DefaultIsNotMerge) {
@ -4230,7 +4230,7 @@ TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_DefaultIsNotMerge) {
ASSERT_NE(bi30->default_head_for, nullptr); ASSERT_NE(bi30->default_head_for, nullptr);
EXPECT_EQ(bi30->default_head_for->begin_id, 10u); EXPECT_EQ(bi30->default_head_for->begin_id, 10u);
EXPECT_FALSE(bi30->default_is_merge); EXPECT_FALSE(bi30->default_is_merge);
EXPECT_EQ(bi30->case_values.get(), nullptr); EXPECT_FALSE(bi30->case_values.has_value());
} }
TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseIsNotDefault) { TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseIsNotDefault) {
@ -4268,7 +4268,7 @@ TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseIsNotDefault) {
EXPECT_EQ(bi20->case_head_for->begin_id, 10u); EXPECT_EQ(bi20->case_head_for->begin_id, 10u);
EXPECT_EQ(bi20->default_head_for, nullptr); EXPECT_EQ(bi20->default_head_for, nullptr);
EXPECT_FALSE(bi20->default_is_merge); EXPECT_FALSE(bi20->default_is_merge);
EXPECT_THAT(*(bi20->case_values.get()), UnorderedElementsAre(200)); EXPECT_THAT(bi20->case_values.value(), UnorderedElementsAre(200));
} }
TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseIsDefault) { TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseIsDefault) {
@ -4303,7 +4303,7 @@ TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseIsDefault) {
EXPECT_EQ(bi20->case_head_for->begin_id, 10u); EXPECT_EQ(bi20->case_head_for->begin_id, 10u);
EXPECT_EQ(bi20->default_head_for, bi20->case_head_for); EXPECT_EQ(bi20->default_head_for, bi20->case_head_for);
EXPECT_FALSE(bi20->default_is_merge); EXPECT_FALSE(bi20->default_is_merge);
EXPECT_THAT(*(bi20->case_values.get()), UnorderedElementsAre(200)); EXPECT_THAT(bi20->case_values.value(), UnorderedElementsAre(200));
} }
TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_ManyCasesWithSameValue_IsError) { TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_ManyCasesWithSameValue_IsError) {
@ -4370,7 +4370,7 @@ TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_ManyValuesWithSameCase) {
EXPECT_EQ(bi20->case_head_for->begin_id, 10u); EXPECT_EQ(bi20->case_head_for->begin_id, 10u);
EXPECT_EQ(bi20->default_head_for, nullptr); EXPECT_EQ(bi20->default_head_for, nullptr);
EXPECT_FALSE(bi20->default_is_merge); EXPECT_FALSE(bi20->default_is_merge);
EXPECT_THAT(*(bi20->case_values.get()), UnorderedElementsAre(200, 300)); EXPECT_THAT(bi20->case_values.value(), UnorderedElementsAre(200, 300));
} }
TEST_F(SpvParserCFGTest, ClassifyCFGEdges_BranchEscapesIfConstruct) { TEST_F(SpvParserCFGTest, ClassifyCFGEdges_BranchEscapesIfConstruct) {

View File

@ -447,10 +447,10 @@ std::string ParserImpl::ShowType(uint32_t type_id) {
return "SPIR-V type " + std::to_string(type_id); return "SPIR-V type " + std::to_string(type_id);
} }
ast::AttributeList ParserImpl::ConvertMemberDecoration(uint32_t struct_type_id, ParserImpl::AttributeList ParserImpl::ConvertMemberDecoration(uint32_t struct_type_id,
uint32_t member_index, uint32_t member_index,
const Type* member_ty, const Type* member_ty,
const Decoration& decoration) { const Decoration& decoration) {
if (decoration.empty()) { if (decoration.empty()) {
Fail() << "malformed SPIR-V decoration: it's empty"; Fail() << "malformed SPIR-V decoration: it's empty";
return {}; return {};
@ -1067,7 +1067,7 @@ const Type* ParserImpl::ConvertType(uint32_t type_id,
} }
// Compute members // Compute members
ast::StructMemberList ast_members; utils::Vector<const ast::StructMember*, 8> ast_members;
const auto members = struct_ty->element_types(); const auto members = struct_ty->element_types();
if (members.empty()) { if (members.empty()) {
Fail() << "WGSL does not support empty structures. can't convert type: " Fail() << "WGSL does not support empty structures. can't convert type: "
@ -1123,7 +1123,7 @@ const Type* ParserImpl::ConvertType(uint32_t type_id,
} }
bool is_non_writable = false; bool is_non_writable = false;
ast::AttributeList ast_member_decorations; AttributeList ast_member_decorations;
for (auto& decoration : GetDecorationsForMember(type_id, member_index)) { for (auto& decoration : GetDecorationsForMember(type_id, member_index)) {
if (IsPipelineDecoration(decoration)) { if (IsPipelineDecoration(decoration)) {
// IO decorations are handled when emitting the entry point. // IO decorations are handled when emitting the entry point.
@ -1137,7 +1137,7 @@ const Type* ParserImpl::ConvertType(uint32_t type_id,
auto decos = auto decos =
ConvertMemberDecoration(type_id, member_index, ast_member_ty, decoration); ConvertMemberDecoration(type_id, member_index, ast_member_ty, decoration);
for (auto* deco : decos) { for (auto* deco : decos) {
ast_member_decorations.emplace_back(deco); ast_member_decorations.Push(deco);
} }
if (!success_) { if (!success_) {
return nullptr; return nullptr;
@ -1154,10 +1154,10 @@ const Type* ParserImpl::ConvertType(uint32_t type_id,
auto* ast_struct_member = create<ast::StructMember>( auto* ast_struct_member = create<ast::StructMember>(
Source{}, builder_.Symbols().Register(member_name), ast_member_ty->Build(builder_), Source{}, builder_.Symbols().Register(member_name), ast_member_ty->Build(builder_),
std::move(ast_member_decorations)); std::move(ast_member_decorations));
ast_members.push_back(ast_struct_member); ast_members.Push(ast_struct_member);
} }
if (ast_members.empty()) { if (ast_members.IsEmpty()) {
// All members were likely built-ins. Don't generate an empty AST structure. // All members were likely built-ins. Don't generate an empty AST structure.
return nullptr; return nullptr;
} }
@ -1168,8 +1168,7 @@ const Type* ParserImpl::ConvertType(uint32_t type_id,
// Now make the struct. // Now make the struct.
auto sym = builder_.Symbols().Register(name); auto sym = builder_.Symbols().Register(name);
auto* ast_struct = auto* ast_struct = create<ast::Struct>(Source{}, sym, std::move(ast_members), utils::Empty);
create<ast::Struct>(Source{}, sym, std::move(ast_members), ast::AttributeList());
if (num_non_writable_members == members.size()) { if (num_non_writable_members == members.size()) {
read_only_struct_types_.insert(ast_struct->name); read_only_struct_types_.insert(ast_struct->name);
} }
@ -1358,7 +1357,7 @@ bool ParserImpl::EmitScalarSpecConstants() {
break; break;
} }
if (ast_type && ast_expr) { if (ast_type && ast_expr) {
ast::AttributeList spec_id_decos; AttributeList spec_id_decos;
for (const auto& deco : GetDecorationsFor(inst.result_id())) { for (const auto& deco : GetDecorationsFor(inst.result_id())) {
if ((deco.size() == 2) && (deco[0] == SpvDecorationSpecId)) { if ((deco.size() == 2) && (deco[0] == SpvDecorationSpecId)) {
const uint32_t id = deco[1]; const uint32_t id = deco[1];
@ -1368,7 +1367,7 @@ bool ParserImpl::EmitScalarSpecConstants() {
<< inst.result_id() << " has SpecId " << id; << inst.result_id() << " has SpecId " << id;
} }
auto* cid = create<ast::IdAttribute>(Source{}, id); auto* cid = create<ast::IdAttribute>(Source{}, id);
spec_id_decos.push_back(cid); spec_id_decos.Push(cid);
break; break;
} }
} }
@ -1491,7 +1490,7 @@ bool ParserImpl::EmitModuleScopeVariables() {
ast_constructor = MakeConstantExpression(var.GetSingleWordInOperand(1)).expr; ast_constructor = MakeConstantExpression(var.GetSingleWordInOperand(1)).expr;
} }
auto* ast_var = MakeVar(var.result_id(), ast_storage_class, ast_store_type, ast_constructor, auto* ast_var = MakeVar(var.result_id(), ast_storage_class, ast_store_type, ast_constructor,
ast::AttributeList{}); utils::Empty);
// TODO(dneto): initializers (a.k.a. constructor expression) // TODO(dneto): initializers (a.k.a. constructor expression)
if (ast_var) { if (ast_var) {
builder_.AST().AddGlobalVariable(ast_var); builder_.AST().AddGlobalVariable(ast_var);
@ -1558,7 +1557,7 @@ ast::Var* ParserImpl::MakeVar(uint32_t id,
ast::StorageClass sc, ast::StorageClass sc,
const Type* storage_type, const Type* storage_type,
const ast::Expression* constructor, const ast::Expression* constructor,
ast::AttributeList decorations) { AttributeList decorations) {
if (storage_type == nullptr) { if (storage_type == nullptr) {
Fail() << "internal error: can't make ast::Variable for null type"; Fail() << "internal error: can't make ast::Variable for null type";
return nullptr; return nullptr;
@ -1593,14 +1592,13 @@ ast::Var* ParserImpl::MakeVar(uint32_t id,
ast::Let* ParserImpl::MakeLet(uint32_t id, const Type* type, const ast::Expression* constructor) { ast::Let* ParserImpl::MakeLet(uint32_t id, const Type* type, const ast::Expression* constructor) {
auto sym = builder_.Symbols().Register(namer_.Name(id)); auto sym = builder_.Symbols().Register(namer_.Name(id));
return create<ast::Let>(Source{}, sym, type->Build(builder_), constructor, return create<ast::Let>(Source{}, sym, type->Build(builder_), constructor, utils::Empty);
ast::AttributeList{});
} }
ast::Override* ParserImpl::MakeOverride(uint32_t id, ast::Override* ParserImpl::MakeOverride(uint32_t id,
const Type* type, const Type* type,
const ast::Expression* constructor, const ast::Expression* constructor,
ast::AttributeList decorations) { AttributeList decorations) {
if (!ConvertDecorationsForVariable(id, &type, &decorations, false)) { if (!ConvertDecorationsForVariable(id, &type, &decorations, false)) {
return nullptr; return nullptr;
} }
@ -1610,7 +1608,7 @@ ast::Override* ParserImpl::MakeOverride(uint32_t id,
ast::Parameter* ParserImpl::MakeParameter(uint32_t id, ast::Parameter* ParserImpl::MakeParameter(uint32_t id,
const Type* type, const Type* type,
ast::AttributeList decorations) { AttributeList decorations) {
if (!ConvertDecorationsForVariable(id, &type, &decorations, false)) { if (!ConvertDecorationsForVariable(id, &type, &decorations, false)) {
return nullptr; return nullptr;
} }
@ -1621,7 +1619,7 @@ ast::Parameter* ParserImpl::MakeParameter(uint32_t id,
bool ParserImpl::ConvertDecorationsForVariable(uint32_t id, bool ParserImpl::ConvertDecorationsForVariable(uint32_t id,
const Type** store_type, const Type** store_type,
ast::AttributeList* decorations, AttributeList* decorations,
bool transfer_pipeline_io) { bool transfer_pipeline_io) {
DecorationList non_builtin_pipeline_decorations; DecorationList non_builtin_pipeline_decorations;
for (auto& deco : GetDecorationsFor(id)) { for (auto& deco : GetDecorationsFor(id)) {
@ -1681,7 +1679,7 @@ bool ParserImpl::ConvertDecorationsForVariable(uint32_t id,
return false; return false;
} }
if (transfer_pipeline_io) { if (transfer_pipeline_io) {
decorations->emplace_back(create<ast::BuiltinAttribute>(Source{}, ast_builtin)); decorations->Push(create<ast::BuiltinAttribute>(Source{}, ast_builtin));
} }
} }
if (transfer_pipeline_io && IsPipelineDecoration(deco)) { if (transfer_pipeline_io && IsPipelineDecoration(deco)) {
@ -1692,13 +1690,13 @@ bool ParserImpl::ConvertDecorationsForVariable(uint32_t id,
return Fail() << "malformed DescriptorSet decoration on ID " << id return Fail() << "malformed DescriptorSet decoration on ID " << id
<< ": has no operand"; << ": has no operand";
} }
decorations->emplace_back(create<ast::GroupAttribute>(Source{}, deco[1])); decorations->Push(create<ast::GroupAttribute>(Source{}, deco[1]));
} }
if (deco[0] == SpvDecorationBinding) { if (deco[0] == SpvDecorationBinding) {
if (deco.size() == 1) { if (deco.size() == 1) {
return Fail() << "malformed Binding decoration on ID " << id << ": has no operand"; return Fail() << "malformed Binding decoration on ID " << id << ": has no operand";
} }
decorations->emplace_back(create<ast::BindingAttribute>(Source{}, deco[1])); decorations->Push(create<ast::BindingAttribute>(Source{}, deco[1]));
} }
} }
@ -1725,7 +1723,7 @@ DecorationList ParserImpl::GetMemberPipelineDecorations(const Struct& struct_typ
return result; return result;
} }
const ast::Attribute* ParserImpl::SetLocation(ast::AttributeList* attributes, const ast::Attribute* ParserImpl::SetLocation(AttributeList* attributes,
const ast::Attribute* replacement) { const ast::Attribute* replacement) {
if (!replacement) { if (!replacement) {
return nullptr; return nullptr;
@ -1742,13 +1740,13 @@ const ast::Attribute* ParserImpl::SetLocation(ast::AttributeList* attributes,
} }
} }
// The list didn't have a location. Add it. // The list didn't have a location. Add it.
attributes->push_back(replacement); attributes->Push(replacement);
return nullptr; return nullptr;
} }
bool ParserImpl::ConvertPipelineDecorations(const Type* store_type, bool ParserImpl::ConvertPipelineDecorations(const Type* store_type,
const DecorationList& decorations, const DecorationList& decorations,
ast::AttributeList* attributes) { AttributeList* attributes) {
// Vulkan defaults to perspective-correct interpolation. // Vulkan defaults to perspective-correct interpolation.
ast::InterpolationType type = ast::InterpolationType::kPerspective; ast::InterpolationType type = ast::InterpolationType::kPerspective;
ast::InterpolationSampling sampling = ast::InterpolationSampling::kNone; ast::InterpolationSampling sampling = ast::InterpolationSampling::kNone;
@ -1809,7 +1807,7 @@ bool ParserImpl::ConvertPipelineDecorations(const Type* store_type,
sampling == ast::InterpolationSampling::kNone) { sampling == ast::InterpolationSampling::kNone) {
// This is the default. Don't add a decoration. // This is the default. Don't add a decoration.
} else { } else {
attributes->emplace_back(create<ast::InterpolateAttribute>(type, sampling)); attributes->Push(create<ast::InterpolateAttribute>(type, sampling));
} }
return success(); return success();
@ -1842,7 +1840,7 @@ TypedExpression ParserImpl::MakeConstantExpression(uint32_t id) {
auto z = MakeConstantExpression(workgroup_size_builtin_.z_id); auto z = MakeConstantExpression(workgroup_size_builtin_.z_id);
auto* ast_type = ty_.Vector(x.type, 3); auto* ast_type = ty_.Vector(x.type, 3);
return {ast_type, builder_.Construct(Source{}, ast_type->Build(builder_), return {ast_type, builder_.Construct(Source{}, ast_type->Build(builder_),
ast::ExpressionList{x.expr, y.expr, z.expr})}; utils::Vector{x.expr, y.expr, z.expr})};
} else if (id == workgroup_size_builtin_.x_id) { } else if (id == workgroup_size_builtin_.x_id) {
return MakeConstantExpressionForScalarSpirvConstant( return MakeConstantExpressionForScalarSpirvConstant(
Source{}, ConvertType(workgroup_size_builtin_.component_type_id), Source{}, ConvertType(workgroup_size_builtin_.component_type_id),
@ -1898,14 +1896,14 @@ TypedExpression ParserImpl::MakeConstantExpression(uint32_t id) {
// Handle vector, matrix, array, and struct // Handle vector, matrix, array, and struct
// Generate a composite from explicit components. // Generate a composite from explicit components.
ast::ExpressionList ast_components; ExpressionList ast_components;
if (!inst->WhileEachInId([&](const uint32_t* id_ref) -> bool { if (!inst->WhileEachInId([&](const uint32_t* id_ref) -> bool {
auto component = MakeConstantExpression(*id_ref); auto component = MakeConstantExpression(*id_ref);
if (!component) { if (!component) {
this->Fail() << "invalid constant with ID " << *id_ref; this->Fail() << "invalid constant with ID " << *id_ref;
return false; return false;
} }
ast_components.emplace_back(component.expr); ast_components.Push(component.expr);
return true; return true;
})) { })) {
// We've already emitted a diagnostic. // We've already emitted a diagnostic.
@ -1996,9 +1994,9 @@ const ast::Expression* ParserImpl::MakeNullValue(const Type* type) {
[&](const Array*) { return builder_.Construct(Source{}, type->Build(builder_)); }, [&](const Array*) { return builder_.Construct(Source{}, type->Build(builder_)); },
[&](const Bool*) { return create<ast::BoolLiteralExpression>(Source{}, false); }, [&](const Bool*) { return create<ast::BoolLiteralExpression>(Source{}, false); },
[&](const Struct* struct_ty) { [&](const Struct* struct_ty) {
ast::ExpressionList ast_components; ExpressionList ast_components;
for (auto* member : struct_ty->members) { for (auto* member : struct_ty->members) {
ast_components.emplace_back(MakeNullValue(member)); ast_components.Push(MakeNullValue(member));
} }
return builder_.Construct(Source{}, original_type->Build(builder_), return builder_.Construct(Source{}, original_type->Build(builder_),
std::move(ast_components)); std::move(ast_components));

View File

@ -123,6 +123,9 @@ struct WorkgroupSizeInfo {
/// Parser implementation for SPIR-V. /// Parser implementation for SPIR-V.
class ParserImpl : Reader { class ParserImpl : Reader {
using AttributeList = utils::Vector<const ast::Attribute*, 8>;
using ExpressionList = utils::Vector<const ast::Expression*, 8>;
public: public:
/// Creates a new parser /// Creates a new parser
/// @param input the input data to parse /// @param input the input data to parse
@ -252,15 +255,14 @@ class ParserImpl : Reader {
/// a diagnostic), or when the variable should not be emitted, e.g. for a /// a diagnostic), or when the variable should not be emitted, e.g. for a
/// PointSize builtin. /// PointSize builtin.
/// @param id the ID of the SPIR-V variable /// @param id the ID of the SPIR-V variable
/// @param store_type the WGSL store type for the variable, which should be /// @param store_type the WGSL store type for the variable, which should be prepopulated
/// prepopulatd
/// @param attributes the attribute list to populate /// @param attributes the attribute list to populate
/// @param transfer_pipeline_io true if pipeline IO decorations (builtins, /// @param transfer_pipeline_io true if pipeline IO decorations (builtins,
/// or locations) will update the store type and the decorations list /// or locations) will update the store type and the decorations list
/// @returns false when the variable should not be emitted as a variable /// @returns false when the variable should not be emitted as a variable
bool ConvertDecorationsForVariable(uint32_t id, bool ConvertDecorationsForVariable(uint32_t id,
const Type** store_type, const Type** store_type,
ast::AttributeList* attributes, AttributeList* attributes,
bool transfer_pipeline_io); bool transfer_pipeline_io);
/// Converts SPIR-V decorations for pipeline IO into AST decorations. /// Converts SPIR-V decorations for pipeline IO into AST decorations.
@ -270,7 +272,7 @@ class ParserImpl : Reader {
/// @returns false if conversion fails /// @returns false if conversion fails
bool ConvertPipelineDecorations(const Type* store_type, bool ConvertPipelineDecorations(const Type* store_type,
const DecorationList& decorations, const DecorationList& decorations,
ast::AttributeList* attributes); AttributeList* attributes);
/// Updates the attribute list, placing a non-null location decoration into /// Updates the attribute list, placing a non-null location decoration into
/// the list, replacing an existing one if it exists. Does nothing if the /// the list, replacing an existing one if it exists. Does nothing if the
@ -280,7 +282,7 @@ class ParserImpl : Reader {
/// @param replacement the location decoration to place into the list /// @param replacement the location decoration to place into the list
/// @returns the location decoration that was replaced, if one was replaced, /// @returns the location decoration that was replaced, if one was replaced,
/// or null otherwise. /// or null otherwise.
const ast::Attribute* SetLocation(ast::AttributeList* decos, const ast::Attribute* replacement); const ast::Attribute* SetLocation(AttributeList* decos, const ast::Attribute* replacement);
/// Converts a SPIR-V struct member decoration into a number of AST /// Converts a SPIR-V struct member decoration into a number of AST
/// decorations. If the decoration is recognized but deliberately dropped, /// decorations. If the decoration is recognized but deliberately dropped,
@ -291,10 +293,10 @@ class ParserImpl : Reader {
/// @param member_ty the type of the member /// @param member_ty the type of the member
/// @param decoration an encoded SPIR-V Decoration /// @param decoration an encoded SPIR-V Decoration
/// @returns the AST decorations /// @returns the AST decorations
ast::AttributeList ConvertMemberDecoration(uint32_t struct_type_id, AttributeList ConvertMemberDecoration(uint32_t struct_type_id,
uint32_t member_index, uint32_t member_index,
const Type* member_ty, const Type* member_ty,
const Decoration& decoration); const Decoration& decoration);
/// Returns a string for the given type. If the type ID is invalid, /// Returns a string for the given type. If the type ID is invalid,
/// then the resulting string only names the type ID. /// then the resulting string only names the type ID.
@ -434,7 +436,7 @@ class ParserImpl : Reader {
ast::StorageClass sc, ast::StorageClass sc,
const Type* storage_type, const Type* storage_type,
const ast::Expression* constructor, const ast::Expression* constructor,
ast::AttributeList decorations); AttributeList decorations);
/// Creates an AST 'let' node for a SPIR-V ID, including any attached decorations,. /// Creates an AST 'let' node for a SPIR-V ID, including any attached decorations,.
/// @param id the SPIR-V result ID /// @param id the SPIR-V result ID
@ -452,7 +454,7 @@ class ParserImpl : Reader {
ast::Override* MakeOverride(uint32_t id, ast::Override* MakeOverride(uint32_t id,
const Type* type, const Type* type,
const ast::Expression* constructor, const ast::Expression* constructor,
ast::AttributeList decorations); AttributeList decorations);
/// Creates an AST parameter node for a SPIR-V ID, including any attached decorations, unless /// Creates an AST parameter node for a SPIR-V ID, including any attached decorations, unless
/// it's an ignorable builtin variable. /// it's an ignorable builtin variable.
@ -460,7 +462,7 @@ class ParserImpl : Reader {
/// @param type the type of the parameter /// @param type the type of the parameter
/// @param decorations the parameter decorations /// @param decorations the parameter decorations
/// @returns the AST parameter node /// @returns the AST parameter node
ast::Parameter* MakeParameter(uint32_t id, const Type* type, ast::AttributeList decorations); ast::Parameter* MakeParameter(uint32_t id, const Type* type, AttributeList decorations);
/// Returns true if a constant expression can be generated. /// Returns true if a constant expression can be generated.
/// @param id the SPIR-V ID of the value /// @param id the SPIR-V ID of the value

View File

@ -65,10 +65,10 @@ TEST_F(SpvParserTest, WorkgroupBarrier) {
ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str(); ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
auto* helper = program.AST().Functions().Find(program.Symbols().Get("helper")); auto* helper = program.AST().Functions().Find(program.Symbols().Get("helper"));
ASSERT_NE(helper, nullptr); ASSERT_NE(helper, nullptr);
ASSERT_GT(helper->body->statements.size(), 0u); ASSERT_GT(helper->body->statements.Length(), 0u);
auto* call = helper->body->statements[0]->As<ast::CallStatement>(); auto* call = helper->body->statements[0]->As<ast::CallStatement>();
ASSERT_NE(call, nullptr); ASSERT_NE(call, nullptr);
EXPECT_EQ(call->expr->args.size(), 0u); EXPECT_EQ(call->expr->args.Length(), 0u);
auto* sem_call = program.Sem().Get<sem::Call>(call->expr); auto* sem_call = program.Sem().Get<sem::Call>(call->expr);
ASSERT_NE(sem_call, nullptr); ASSERT_NE(sem_call, nullptr);
auto* builtin = sem_call->Target()->As<sem::Builtin>(); auto* builtin = sem_call->Target()->As<sem::Builtin>();
@ -98,10 +98,10 @@ TEST_F(SpvParserTest, StorageBarrier) {
ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str(); ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
auto* helper = program.AST().Functions().Find(program.Symbols().Get("helper")); auto* helper = program.AST().Functions().Find(program.Symbols().Get("helper"));
ASSERT_NE(helper, nullptr); ASSERT_NE(helper, nullptr);
ASSERT_GT(helper->body->statements.size(), 0u); ASSERT_GT(helper->body->statements.Length(), 0u);
auto* call = helper->body->statements[0]->As<ast::CallStatement>(); auto* call = helper->body->statements[0]->As<ast::CallStatement>();
ASSERT_NE(call, nullptr); ASSERT_NE(call, nullptr);
EXPECT_EQ(call->expr->args.size(), 0u); EXPECT_EQ(call->expr->args.Length(), 0u);
auto* sem_call = program.Sem().Get<sem::Call>(call->expr); auto* sem_call = program.Sem().Get<sem::Call>(call->expr);
ASSERT_NE(sem_call, nullptr); ASSERT_NE(sem_call, nullptr);
auto* builtin = sem_call->Target()->As<sem::Builtin>(); auto* builtin = sem_call->Target()->As<sem::Builtin>();

View File

@ -20,11 +20,11 @@ namespace {
using ::testing::Eq; using ::testing::Eq;
TEST_F(SpvParserTest, ConvertMemberDecoration_Empty) { TEST_F(SpvParserTest, ConvertMemberDecoration_IsEmpty) {
auto p = parser(std::vector<uint32_t>{}); auto p = parser(std::vector<uint32_t>{});
auto result = p->ConvertMemberDecoration(1, 1, nullptr, {}); auto result = p->ConvertMemberDecoration(1, 1, nullptr, {});
EXPECT_TRUE(result.empty()); EXPECT_TRUE(result.IsEmpty());
EXPECT_THAT(p->error(), Eq("malformed SPIR-V decoration: it's empty")); EXPECT_THAT(p->error(), Eq("malformed SPIR-V decoration: it's empty"));
} }
@ -32,7 +32,7 @@ TEST_F(SpvParserTest, ConvertMemberDecoration_OffsetWithoutOperand) {
auto p = parser(std::vector<uint32_t>{}); auto p = parser(std::vector<uint32_t>{});
auto result = p->ConvertMemberDecoration(12, 13, nullptr, {SpvDecorationOffset}); auto result = p->ConvertMemberDecoration(12, 13, nullptr, {SpvDecorationOffset});
EXPECT_TRUE(result.empty()); EXPECT_TRUE(result.IsEmpty());
EXPECT_THAT(p->error(), Eq("malformed Offset decoration: expected 1 literal " EXPECT_THAT(p->error(), Eq("malformed Offset decoration: expected 1 literal "
"operand, has 0: member 13 of SPIR-V type 12")); "operand, has 0: member 13 of SPIR-V type 12"));
} }
@ -41,7 +41,7 @@ TEST_F(SpvParserTest, ConvertMemberDecoration_OffsetWithTooManyOperands) {
auto p = parser(std::vector<uint32_t>{}); auto p = parser(std::vector<uint32_t>{});
auto result = p->ConvertMemberDecoration(12, 13, nullptr, {SpvDecorationOffset, 3, 4}); auto result = p->ConvertMemberDecoration(12, 13, nullptr, {SpvDecorationOffset, 3, 4});
EXPECT_TRUE(result.empty()); EXPECT_TRUE(result.IsEmpty());
EXPECT_THAT(p->error(), Eq("malformed Offset decoration: expected 1 literal " EXPECT_THAT(p->error(), Eq("malformed Offset decoration: expected 1 literal "
"operand, has 2: member 13 of SPIR-V type 12")); "operand, has 2: member 13 of SPIR-V type 12"));
} }
@ -50,7 +50,7 @@ TEST_F(SpvParserTest, ConvertMemberDecoration_Offset) {
auto p = parser(std::vector<uint32_t>{}); auto p = parser(std::vector<uint32_t>{});
auto result = p->ConvertMemberDecoration(1, 1, nullptr, {SpvDecorationOffset, 8}); auto result = p->ConvertMemberDecoration(1, 1, nullptr, {SpvDecorationOffset, 8});
ASSERT_FALSE(result.empty()); ASSERT_FALSE(result.IsEmpty());
EXPECT_TRUE(result[0]->Is<ast::StructMemberOffsetAttribute>()); EXPECT_TRUE(result[0]->Is<ast::StructMemberOffsetAttribute>());
auto* offset_deco = result[0]->As<ast::StructMemberOffsetAttribute>(); auto* offset_deco = result[0]->As<ast::StructMemberOffsetAttribute>();
ASSERT_NE(offset_deco, nullptr); ASSERT_NE(offset_deco, nullptr);
@ -64,7 +64,7 @@ TEST_F(SpvParserTest, ConvertMemberDecoration_Matrix2x2_Stride_Natural) {
spirv::F32 f32; spirv::F32 f32;
spirv::Matrix matrix(&f32, 2, 2); spirv::Matrix matrix(&f32, 2, 2);
auto result = p->ConvertMemberDecoration(1, 1, &matrix, {SpvDecorationMatrixStride, 8}); auto result = p->ConvertMemberDecoration(1, 1, &matrix, {SpvDecorationMatrixStride, 8});
EXPECT_TRUE(result.empty()); EXPECT_TRUE(result.IsEmpty());
EXPECT_TRUE(p->error().empty()); EXPECT_TRUE(p->error().empty());
} }
@ -74,7 +74,7 @@ TEST_F(SpvParserTest, ConvertMemberDecoration_Matrix2x2_Stride_Custom) {
spirv::F32 f32; spirv::F32 f32;
spirv::Matrix matrix(&f32, 2, 2); spirv::Matrix matrix(&f32, 2, 2);
auto result = p->ConvertMemberDecoration(1, 1, &matrix, {SpvDecorationMatrixStride, 16}); auto result = p->ConvertMemberDecoration(1, 1, &matrix, {SpvDecorationMatrixStride, 16});
ASSERT_FALSE(result.empty()); ASSERT_FALSE(result.IsEmpty());
EXPECT_TRUE(result[0]->Is<ast::StrideAttribute>()); EXPECT_TRUE(result[0]->Is<ast::StrideAttribute>());
auto* stride_deco = result[0]->As<ast::StrideAttribute>(); auto* stride_deco = result[0]->As<ast::StrideAttribute>();
ASSERT_NE(stride_deco, nullptr); ASSERT_NE(stride_deco, nullptr);
@ -88,7 +88,7 @@ TEST_F(SpvParserTest, ConvertMemberDecoration_Matrix2x4_Stride_Natural) {
spirv::F32 f32; spirv::F32 f32;
spirv::Matrix matrix(&f32, 2, 4); spirv::Matrix matrix(&f32, 2, 4);
auto result = p->ConvertMemberDecoration(1, 1, &matrix, {SpvDecorationMatrixStride, 16}); auto result = p->ConvertMemberDecoration(1, 1, &matrix, {SpvDecorationMatrixStride, 16});
EXPECT_TRUE(result.empty()); EXPECT_TRUE(result.IsEmpty());
EXPECT_TRUE(p->error().empty()); EXPECT_TRUE(p->error().empty());
} }
@ -98,7 +98,7 @@ TEST_F(SpvParserTest, ConvertMemberDecoration_Matrix2x4_Stride_Custom) {
spirv::F32 f32; spirv::F32 f32;
spirv::Matrix matrix(&f32, 2, 4); spirv::Matrix matrix(&f32, 2, 4);
auto result = p->ConvertMemberDecoration(1, 1, &matrix, {SpvDecorationMatrixStride, 64}); auto result = p->ConvertMemberDecoration(1, 1, &matrix, {SpvDecorationMatrixStride, 64});
ASSERT_FALSE(result.empty()); ASSERT_FALSE(result.IsEmpty());
EXPECT_TRUE(result[0]->Is<ast::StrideAttribute>()); EXPECT_TRUE(result[0]->Is<ast::StrideAttribute>());
auto* stride_deco = result[0]->As<ast::StrideAttribute>(); auto* stride_deco = result[0]->As<ast::StrideAttribute>();
ASSERT_NE(stride_deco, nullptr); ASSERT_NE(stride_deco, nullptr);
@ -112,7 +112,7 @@ TEST_F(SpvParserTest, ConvertMemberDecoration_Matrix2x3_Stride_Custom) {
spirv::F32 f32; spirv::F32 f32;
spirv::Matrix matrix(&f32, 2, 3); spirv::Matrix matrix(&f32, 2, 3);
auto result = p->ConvertMemberDecoration(1, 1, &matrix, {SpvDecorationMatrixStride, 32}); auto result = p->ConvertMemberDecoration(1, 1, &matrix, {SpvDecorationMatrixStride, 32});
ASSERT_FALSE(result.empty()); ASSERT_FALSE(result.IsEmpty());
EXPECT_TRUE(result[0]->Is<ast::StrideAttribute>()); EXPECT_TRUE(result[0]->Is<ast::StrideAttribute>());
auto* stride_deco = result[0]->As<ast::StrideAttribute>(); auto* stride_deco = result[0]->As<ast::StrideAttribute>();
ASSERT_NE(stride_deco, nullptr); ASSERT_NE(stride_deco, nullptr);
@ -127,7 +127,7 @@ TEST_F(SpvParserTest, ConvertMemberDecoration_RelaxedPrecision) {
auto p = parser(std::vector<uint32_t>{}); auto p = parser(std::vector<uint32_t>{});
auto result = p->ConvertMemberDecoration(1, 1, nullptr, {SpvDecorationRelaxedPrecision}); auto result = p->ConvertMemberDecoration(1, 1, nullptr, {SpvDecorationRelaxedPrecision});
EXPECT_TRUE(result.empty()); EXPECT_TRUE(result.IsEmpty());
EXPECT_TRUE(p->error().empty()); EXPECT_TRUE(p->error().empty());
} }
@ -135,7 +135,7 @@ TEST_F(SpvParserTest, ConvertMemberDecoration_UnhandledDecoration) {
auto p = parser(std::vector<uint32_t>{}); auto p = parser(std::vector<uint32_t>{});
auto result = p->ConvertMemberDecoration(12, 13, nullptr, {12345678}); auto result = p->ConvertMemberDecoration(12, 13, nullptr, {12345678});
EXPECT_TRUE(result.empty()); EXPECT_TRUE(result.IsEmpty());
EXPECT_THAT(p->error(), Eq("unhandled member decoration: 12345678 on member " EXPECT_THAT(p->error(), Eq("unhandled member decoration: 12345678 on member "
"13 of SPIR-V type 12")); "13 of SPIR-V type 12"));
} }

View File

@ -3076,7 +3076,7 @@ TEST_P(SpvParserHandleTest_ImageCoordsTest, MakeCoordinateOperandsForImageAccess
ASSERT_NE(anchor, nullptr); ASSERT_NE(anchor, nullptr);
const spvtools::opt::Instruction& image_access = *(anchor->PreviousNode()); const spvtools::opt::Instruction& image_access = *(anchor->PreviousNode());
ast::ExpressionList result = fe.MakeCoordinateOperandsForImageAccess(image_access); auto result = fe.MakeCoordinateOperandsForImageAccess(image_access);
if (GetParam().expected_error.empty()) { if (GetParam().expected_error.empty()) {
EXPECT_TRUE(fe.success()) << p->error(); EXPECT_TRUE(fe.success()) << p->error();
EXPECT_TRUE(p->error().empty()); EXPECT_TRUE(p->error().empty());
@ -3090,7 +3090,7 @@ TEST_P(SpvParserHandleTest_ImageCoordsTest, MakeCoordinateOperandsForImageAccess
} else { } else {
EXPECT_FALSE(fe.success()); EXPECT_FALSE(fe.success());
EXPECT_THAT(p->error(), Eq(GetParam().expected_error)) << assembly; EXPECT_THAT(p->error(), Eq(GetParam().expected_error)) << assembly;
EXPECT_TRUE(result.empty()); EXPECT_TRUE(result.IsEmpty());
} }
} }

View File

@ -39,7 +39,7 @@ std::string ToString(const Program& program) {
return writer.result(); return writer.result();
} }
std::string ToString(const Program& program, const ast::StatementList& stmts) { std::string ToString(const Program& program, utils::VectorRef<const ast::Statement*> stmts) {
writer::wgsl::GeneratorImpl writer(&program); writer::wgsl::GeneratorImpl writer(&program);
for (const auto* stmt : stmts) { for (const auto* stmt : stmts) {
if (!writer.EmitStatement(stmt)) { if (!writer.EmitStatement(stmt)) {

View File

@ -195,10 +195,10 @@ class ParserImplWrapperForTest {
/// @param member_ty the type of the member /// @param member_ty the type of the member
/// @param decoration an encoded SPIR-V Decoration /// @param decoration an encoded SPIR-V Decoration
/// @returns the AST decorations /// @returns the AST decorations
ast::AttributeList ConvertMemberDecoration(uint32_t struct_type_id, auto ConvertMemberDecoration(uint32_t struct_type_id,
uint32_t member_index, uint32_t member_index,
const Type* member_ty, const Type* member_ty,
const Decoration& decoration) { const Decoration& decoration) {
return impl_.ConvertMemberDecoration(struct_type_id, member_index, member_ty, decoration); return impl_.ConvertMemberDecoration(struct_type_id, member_index, member_ty, decoration);
} }
@ -275,7 +275,7 @@ std::string ToString(const Program& program);
/// @param program the Program /// @param program the Program
/// @param stmts the statement list /// @param stmts the statement list
/// @returns the WGSL printed string of a statement list. /// @returns the WGSL printed string of a statement list.
std::string ToString(const Program& program, const ast::StatementList& stmts); std::string ToString(const Program& program, utils::VectorRef<const ast::Statement*> stmts);
/// Returns the WGSL printed string of an AST node. /// Returns the WGSL printed string of an AST node.
/// @param program the Program /// @param program the Program

View File

@ -170,9 +170,9 @@ ParserImpl::FunctionHeader::FunctionHeader(const FunctionHeader&) = default;
ParserImpl::FunctionHeader::FunctionHeader(Source src, ParserImpl::FunctionHeader::FunctionHeader(Source src,
std::string n, std::string n,
ast::ParameterList p, utils::VectorRef<const ast::Parameter*> p,
const ast::Type* ret_ty, const ast::Type* ret_ty,
ast::AttributeList ret_attrs) utils::VectorRef<const ast::Attribute*> ret_attrs)
: source(src), : source(src),
name(n), name(n),
params(std::move(p)), params(std::move(p)),
@ -507,7 +507,7 @@ Maybe<bool> ParserImpl::global_decl() {
// Invalid syntax found - try and determine the best error message // Invalid syntax found - try and determine the best error message
// We have attributes parsed, but nothing to consume them? // We have attributes parsed, but nothing to consume them?
if (attrs.value.size() > 0) { if (attrs.value.Length() > 0) {
return add_error(next(), "expected declaration after attributes"); return add_error(next(), "expected declaration after attributes");
} }
@ -540,7 +540,7 @@ Maybe<bool> ParserImpl::global_decl() {
// global_variable_decl // global_variable_decl
// : variable_attribute_list* variable_decl // : variable_attribute_list* variable_decl
// | variable_attribute_list* variable_decl EQUAL const_expr // | variable_attribute_list* variable_decl EQUAL const_expr
Maybe<const ast::Variable*> ParserImpl::global_variable_decl(ast::AttributeList& attrs) { Maybe<const ast::Variable*> ParserImpl::global_variable_decl(AttributeList& attrs) {
auto decl = variable_decl(); auto decl = variable_decl();
if (decl.errored) { if (decl.errored) {
return Failure::kErrored; return Failure::kErrored;
@ -549,24 +549,26 @@ Maybe<const ast::Variable*> ParserImpl::global_variable_decl(ast::AttributeList&
return Failure::kNoMatch; return Failure::kNoMatch;
} }
const ast::Expression* initalizer = nullptr; const ast::Expression* initializer = nullptr;
if (match(Token::Type::kEqual)) { if (match(Token::Type::kEqual)) {
auto expr = logical_or_expression(); auto expr = logical_or_expression();
if (expr.errored) { if (expr.errored) {
return Failure::kErrored; return Failure::kErrored;
} }
if (!expr.matched) { if (!expr.matched) {
return add_error(peek(), "missing initalizer for 'var' declaration"); return add_error(peek(), "missing initializer for 'var' declaration");
} }
initalizer = expr.value; initializer = expr.value;
} }
TINT_DEFER(attrs.Clear());
return create<ast::Var>(decl->source, // source return create<ast::Var>(decl->source, // source
builder_.Symbols().Register(decl->name), // symbol builder_.Symbols().Register(decl->name), // symbol
decl->type, // type decl->type, // type
decl->storage_class, // storage class decl->storage_class, // storage class
decl->access, // access control decl->access, // access control
initalizer, // initializer initializer, // initializer
std::move(attrs)); // attributes std::move(attrs)); // attributes
} }
@ -575,7 +577,7 @@ Maybe<const ast::Variable*> ParserImpl::global_variable_decl(ast::AttributeList&
// | attribute* override (ident | variable_ident_decl) (equal expression)? // | attribute* override (ident | variable_ident_decl) (equal expression)?
// global_const_initializer // global_const_initializer
// : EQUAL const_expr // : EQUAL const_expr
Maybe<const ast::Variable*> ParserImpl::global_constant_decl(ast::AttributeList& attrs) { Maybe<const ast::Variable*> ParserImpl::global_constant_decl(AttributeList& attrs) {
bool is_const = false; bool is_const = false;
bool is_overridable = false; bool is_overridable = false;
const char* use = nullptr; const char* use = nullptr;
@ -619,6 +621,8 @@ Maybe<const ast::Variable*> ParserImpl::global_constant_decl(ast::AttributeList&
initializer = std::move(expr.value); initializer = std::move(expr.value);
} }
TINT_DEFER(attrs.Clear());
if (is_const) { if (is_const) {
return create<ast::Const>(decl->source, // source return create<ast::Const>(decl->source, // source
builder_.Symbols().Register(decl->name), // symbol builder_.Symbols().Register(decl->name), // symbol
@ -1273,14 +1277,14 @@ Maybe<const ast::Struct*> ParserImpl::struct_decl() {
} }
auto sym = builder_.Symbols().Register(name.value); auto sym = builder_.Symbols().Register(name.value);
return create<ast::Struct>(t.source(), sym, std::move(body.value), ast::AttributeList{}); return create<ast::Struct>(t.source(), sym, std::move(body.value), utils::Empty);
} }
// struct_body_decl // struct_body_decl
// : BRACE_LEFT (struct_member COMMA)* struct_member COMMA? BRACE_RIGHT // : BRACE_LEFT (struct_member COMMA)* struct_member COMMA? BRACE_RIGHT
Expect<ast::StructMemberList> ParserImpl::expect_struct_body_decl() { Expect<ParserImpl::StructMemberList> ParserImpl::expect_struct_body_decl() {
return expect_brace_block("struct declaration", [&]() -> Expect<ast::StructMemberList> { return expect_brace_block("struct declaration", [&]() -> Expect<StructMemberList> {
ast::StructMemberList members; StructMemberList members;
bool errored = false; bool errored = false;
while (continue_parsing()) { while (continue_parsing()) {
// Check for the end of the list. // Check for the end of the list.
@ -1296,7 +1300,7 @@ Expect<ast::StructMemberList> ParserImpl::expect_struct_body_decl() {
return Failure::kErrored; return Failure::kErrored;
} }
} else { } else {
members.push_back(member.value); members.Push(member.value);
} }
if (!match(Token::Type::kComma)) { if (!match(Token::Type::kComma)) {
@ -1330,7 +1334,7 @@ Expect<ast::StructMember*> ParserImpl::expect_struct_member() {
// function_decl // function_decl
// : function_header body_stmt // : function_header body_stmt
Maybe<const ast::Function*> ParserImpl::function_decl(ast::AttributeList& attrs) { Maybe<const ast::Function*> ParserImpl::function_decl(AttributeList& attrs) {
auto header = function_header(); auto header = function_header();
if (header.errored) { if (header.errored) {
if (sync_to(Token::Type::kBraceLeft, /* consume: */ false)) { if (sync_to(Token::Type::kBraceLeft, /* consume: */ false)) {
@ -1359,8 +1363,10 @@ Maybe<const ast::Function*> ParserImpl::function_decl(ast::AttributeList& attrs)
return Failure::kErrored; return Failure::kErrored;
} }
TINT_DEFER(attrs.Clear());
return create<ast::Function>(header->source, builder_.Symbols().Register(header->name), return create<ast::Function>(header->source, builder_.Symbols().Register(header->name),
header->params, header->return_type, body.value, attrs, header->params, header->return_type, body.value, std::move(attrs),
header->return_type_attributes); header->return_type_attributes);
} }
@ -1395,7 +1401,7 @@ Maybe<ParserImpl::FunctionHeader> ParserImpl::function_header() {
} }
const ast::Type* return_type = nullptr; const ast::Type* return_type = nullptr;
ast::AttributeList return_attributes; AttributeList return_attributes;
if (match(Token::Type::kArrow)) { if (match(Token::Type::kArrow)) {
auto attrs = attribute_list(); auto attrs = attribute_list();
@ -1420,15 +1426,17 @@ Maybe<ParserImpl::FunctionHeader> ParserImpl::function_header() {
return Failure::kErrored; return Failure::kErrored;
} }
return FunctionHeader{source, name.value, std::move(params.value), return_type, return FunctionHeader{
std::move(return_attributes)}; source, std::move(name.value), std::move(params.value),
return_type, std::move(return_attributes),
};
} }
// param_list // param_list
// : // :
// | (param COMMA)* param COMMA? // | (param COMMA)* param COMMA?
Expect<ast::ParameterList> ParserImpl::expect_param_list() { Expect<ParserImpl::ParameterList> ParserImpl::expect_param_list() {
ast::ParameterList ret; ParameterList ret;
while (continue_parsing()) { while (continue_parsing()) {
// Check for the end of the list. // Check for the end of the list.
auto& t = peek(); auto& t = peek();
@ -1440,7 +1448,7 @@ Expect<ast::ParameterList> ParserImpl::expect_param_list() {
if (param.errored) { if (param.errored) {
return Failure::kErrored; return Failure::kErrored;
} }
ret.push_back(param.value); ret.Push(param.value);
if (!match(Token::Type::kComma)) { if (!match(Token::Type::kComma)) {
break; break;
@ -1532,16 +1540,16 @@ Expect<const ast::Expression*> ParserImpl::expect_paren_expression() {
// statements // statements
// : statement* // : statement*
Expect<ast::StatementList> ParserImpl::expect_statements() { Expect<ParserImpl::StatementList> ParserImpl::expect_statements() {
bool errored = false; bool errored = false;
ast::StatementList stmts; StatementList stmts;
while (continue_parsing()) { while (continue_parsing()) {
auto stmt = statement(); auto stmt = statement();
if (stmt.errored) { if (stmt.errored) {
errored = true; errored = true;
} else if (stmt.matched) { } else if (stmt.matched) {
stmts.emplace_back(stmt.value); stmts.Push(stmt.value);
} else { } else {
break; break;
} }
@ -1762,7 +1770,7 @@ Maybe<const ast::VariableDeclStatement*> ParserImpl::variable_stmt() {
builder_.Symbols().Register(decl->name), // symbol builder_.Symbols().Register(decl->name), // symbol
decl->type, // type decl->type, // type
initializer.value, // initializer initializer.value, // initializer
ast::AttributeList{}); // attributes utils::Empty); // attributes
return create<ast::VariableDeclStatement>(decl->source, const_); return create<ast::VariableDeclStatement>(decl->source, const_);
} }
@ -1790,7 +1798,7 @@ Maybe<const ast::VariableDeclStatement*> ParserImpl::variable_stmt() {
builder_.Symbols().Register(decl->name), // symbol builder_.Symbols().Register(decl->name), // symbol
decl->type, // type decl->type, // type
initializer.value, // initializer initializer.value, // initializer
ast::AttributeList{}); // attributes utils::Empty); // attributes
return create<ast::VariableDeclStatement>(decl->source, let); return create<ast::VariableDeclStatement>(decl->source, let);
} }
@ -1822,7 +1830,7 @@ Maybe<const ast::VariableDeclStatement*> ParserImpl::variable_stmt() {
decl->storage_class, // storage class decl->storage_class, // storage class
decl->access, // access control decl->access, // access control
initializer, // initializer initializer, // initializer
ast::AttributeList{}); // attributes utils::Empty); // attributes
return create<ast::VariableDeclStatement>(var->source, var); return create<ast::VariableDeclStatement>(var->source, var);
} }
@ -1925,9 +1933,9 @@ Maybe<const ast::SwitchStatement*> ParserImpl::switch_stmt() {
return add_error(peek(), "unable to parse selector expression"); return add_error(peek(), "unable to parse selector expression");
} }
auto body = expect_brace_block("switch statement", [&]() -> Expect<ast::CaseStatementList> { auto body = expect_brace_block("switch statement", [&]() -> Expect<CaseStatementList> {
bool errored = false; bool errored = false;
ast::CaseStatementList list; CaseStatementList list;
while (continue_parsing()) { while (continue_parsing()) {
auto stmt = switch_body(); auto stmt = switch_body();
if (stmt.errored) { if (stmt.errored) {
@ -1937,7 +1945,7 @@ Maybe<const ast::SwitchStatement*> ParserImpl::switch_stmt() {
if (!stmt.matched) { if (!stmt.matched) {
break; break;
} }
list.push_back(stmt.value); list.Push(stmt.value);
} }
if (errored) { if (errored) {
return Failure::kErrored; return Failure::kErrored;
@ -1962,7 +1970,7 @@ Maybe<const ast::CaseStatement*> ParserImpl::switch_body() {
auto& t = next(); auto& t = next();
ast::CaseSelectorList selector_list; CaseSelectorList selector_list;
if (t.Is(Token::Type::kCase)) { if (t.Is(Token::Type::kCase)) {
auto selectors = expect_case_selectors(); auto selectors = expect_case_selectors();
if (selectors.errored) { if (selectors.errored) {
@ -1990,8 +1998,8 @@ Maybe<const ast::CaseStatement*> ParserImpl::switch_body() {
// case_selectors // case_selectors
// : const_literal (COMMA const_literal)* COMMA? // : const_literal (COMMA const_literal)* COMMA?
Expect<ast::CaseSelectorList> ParserImpl::expect_case_selectors() { Expect<ParserImpl::CaseSelectorList> ParserImpl::expect_case_selectors() {
ast::CaseSelectorList selectors; CaseSelectorList selectors;
while (continue_parsing()) { while (continue_parsing()) {
auto cond = const_literal(); auto cond = const_literal();
@ -2003,14 +2011,14 @@ Expect<ast::CaseSelectorList> ParserImpl::expect_case_selectors() {
return add_error(cond.value->source, "invalid case selector must be an integer value"); return add_error(cond.value->source, "invalid case selector must be an integer value");
} }
selectors.push_back(cond.value->As<ast::IntLiteralExpression>()); selectors.Push(cond.value->As<ast::IntLiteralExpression>());
if (!match(Token::Type::kComma)) { if (!match(Token::Type::kComma)) {
break; break;
} }
} }
if (selectors.empty()) { if (selectors.IsEmpty()) {
return add_error(peek(), "unable to parse case selectors"); return add_error(peek(), "unable to parse case selectors");
} }
@ -2022,7 +2030,7 @@ Expect<ast::CaseSelectorList> ParserImpl::expect_case_selectors() {
// | statement case_body // | statement case_body
// | FALLTHROUGH SEMICOLON // | FALLTHROUGH SEMICOLON
Maybe<const ast::BlockStatement*> ParserImpl::case_body() { Maybe<const ast::BlockStatement*> ParserImpl::case_body() {
ast::StatementList stmts; StatementList stmts;
while (continue_parsing()) { while (continue_parsing()) {
Source source; Source source;
if (match(Token::Type::kFallthrough, &source)) { if (match(Token::Type::kFallthrough, &source)) {
@ -2030,7 +2038,7 @@ Maybe<const ast::BlockStatement*> ParserImpl::case_body() {
return Failure::kErrored; return Failure::kErrored;
} }
stmts.emplace_back(create<ast::FallthroughStatement>(source)); stmts.Push(create<ast::FallthroughStatement>(source));
break; break;
} }
@ -2042,7 +2050,7 @@ Maybe<const ast::BlockStatement*> ParserImpl::case_body() {
break; break;
} }
stmts.emplace_back(stmt.value); stmts.Push(stmt.value);
} }
return create<ast::BlockStatement>(Source{}, stmts); return create<ast::BlockStatement>(Source{}, stmts);
@ -2259,7 +2267,7 @@ Maybe<const ast::ContinueStatement*> ParserImpl::continue_stmt() {
// : CONTINUING body_stmt // : CONTINUING body_stmt
Maybe<const ast::BlockStatement*> ParserImpl::continuing_stmt() { Maybe<const ast::BlockStatement*> ParserImpl::continuing_stmt() {
if (!match(Token::Type::kContinuing)) { if (!match(Token::Type::kContinuing)) {
return create<ast::BlockStatement>(Source{}, ast::StatementList{}); return create<ast::BlockStatement>(Source{}, utils::Empty);
} }
return expect_body_stmt(); return expect_body_stmt();
@ -2409,9 +2417,10 @@ Maybe<const ast::Expression*> ParserImpl::singular_expression() {
// argument_expression_list // argument_expression_list
// : PAREN_LEFT ((logical_or_expression COMMA)* logical_or_expression COMMA?)? // : PAREN_LEFT ((logical_or_expression COMMA)* logical_or_expression COMMA?)?
// PAREN_RIGHT // PAREN_RIGHT
Expect<ast::ExpressionList> ParserImpl::expect_argument_expression_list(std::string_view use) { Expect<ParserImpl::ExpressionList> ParserImpl::expect_argument_expression_list(
return expect_paren_block(use, [&]() -> Expect<ast::ExpressionList> { std::string_view use) {
ast::ExpressionList ret; return expect_paren_block(use, [&]() -> Expect<ExpressionList> {
ExpressionList ret;
while (continue_parsing()) { while (continue_parsing()) {
auto arg = logical_or_expression(); auto arg = logical_or_expression();
if (arg.errored) { if (arg.errored) {
@ -2419,7 +2428,7 @@ Expect<ast::ExpressionList> ParserImpl::expect_argument_expression_list(std::str
} else if (!arg.matched) { } else if (!arg.matched) {
break; break;
} }
ret.push_back(arg.value); ret.Push(arg.value);
if (!match(Token::Type::kComma)) { if (!match(Token::Type::kComma)) {
break; break;
@ -3051,16 +3060,16 @@ Maybe<const ast::LiteralExpression*> ParserImpl::const_literal() {
return Failure::kNoMatch; return Failure::kNoMatch;
} }
Maybe<ast::AttributeList> ParserImpl::attribute_list() { Maybe<ParserImpl::AttributeList> ParserImpl::attribute_list() {
bool errored = false; bool errored = false;
ast::AttributeList attrs; AttributeList attrs;
while (continue_parsing()) { while (continue_parsing()) {
if (match(Token::Type::kAttr)) { if (match(Token::Type::kAttr)) {
if (auto attr = expect_attribute(); attr.errored) { if (auto attr = expect_attribute(); attr.errored) {
errored = true; errored = true;
} else { } else {
attrs.emplace_back(attr.value); attrs.Push(attr.value);
} }
} else { } else {
break; break;
@ -3071,7 +3080,7 @@ Maybe<ast::AttributeList> ParserImpl::attribute_list() {
return Failure::kErrored; return Failure::kErrored;
} }
if (attrs.empty()) { if (attrs.IsEmpty()) {
return Failure::kNoMatch; return Failure::kNoMatch;
} }
@ -3312,8 +3321,8 @@ Maybe<const ast::Attribute*> ParserImpl::attribute() {
return Failure::kNoMatch; return Failure::kNoMatch;
} }
bool ParserImpl::expect_attributes_consumed(ast::AttributeList& in) { bool ParserImpl::expect_attributes_consumed(utils::VectorRef<const ast::Attribute*> in) {
if (in.empty()) { if (in.IsEmpty()) {
return true; return true;
} }
add_error(in[0]->source, "unexpected attributes"); add_error(in[0]->source, "unexpected attributes");

View File

@ -71,6 +71,17 @@ class ParserImpl {
}; };
public: public:
/// Pre-determined small vector sizes for AST pointers
//! @cond Doxygen_Suppress
using AttributeList = utils::Vector<const ast::Attribute*, 4>;
using CaseSelectorList = utils::Vector<const ast::IntLiteralExpression*, 4>;
using CaseStatementList = utils::Vector<const ast::CaseStatement*, 4>;
using ExpressionList = utils::Vector<const ast::Expression*, 8>;
using ParameterList = utils::Vector<const ast::Parameter*, 8>;
using StatementList = utils::Vector<const ast::Statement*, 8>;
using StructMemberList = utils::Vector<const ast::StructMember*, 8>;
//! @endcond
/// Expect is the return type of the parser methods that are expected to /// Expect is the return type of the parser methods that are expected to
/// return a parsed value of type T, unless there was an parse error. /// return a parsed value of type T, unless there was an parse error.
/// In the case of a parse error the called method will have called /// In the case of a parse error the called method will have called
@ -231,9 +242,9 @@ class ParserImpl {
/// @param ret_attrs return type attributes /// @param ret_attrs return type attributes
FunctionHeader(Source src, FunctionHeader(Source src,
std::string n, std::string n,
ast::ParameterList p, utils::VectorRef<const ast::Parameter*> p,
const ast::Type* ret_ty, const ast::Type* ret_ty,
ast::AttributeList ret_attrs); utils::VectorRef<const ast::Attribute*> ret_attrs);
/// Destructor /// Destructor
~FunctionHeader(); ~FunctionHeader();
/// Assignment operator /// Assignment operator
@ -246,11 +257,11 @@ class ParserImpl {
/// Function name /// Function name
std::string name; std::string name;
/// Function parameters /// Function parameters
ast::ParameterList params; utils::Vector<const ast::Parameter*, 8> params;
/// Function return type /// Function return type
const ast::Type* return_type = nullptr; const ast::Type* return_type = nullptr;
/// Function return type attributes /// Function return type attributes
ast::AttributeList return_type_attributes; AttributeList return_type_attributes;
}; };
/// VarDeclInfo contains the parsed information for variable declaration. /// VarDeclInfo contains the parsed information for variable declaration.
@ -383,13 +394,15 @@ class ParserImpl {
/// Parses a `global_variable_decl` grammar element with the initial /// Parses a `global_variable_decl` grammar element with the initial
/// `variable_attribute_list*` provided as `attrs` /// `variable_attribute_list*` provided as `attrs`
/// @returns the variable parsed or nullptr /// @returns the variable parsed or nullptr
/// @param attrs the list of attributes for the variable declaration. /// @param attrs the list of attributes for the variable declaration. If attributes are consumed
Maybe<const ast::Variable*> global_variable_decl(ast::AttributeList& attrs); /// by the declaration, then this vector is cleared before returning.
Maybe<const ast::Variable*> global_variable_decl(AttributeList& attrs);
/// Parses a `global_constant_decl` grammar element with the initial /// Parses a `global_constant_decl` grammar element with the initial
/// `variable_attribute_list*` provided as `attrs` /// `variable_attribute_list*` provided as `attrs`
/// @returns the const object or nullptr /// @returns the const object or nullptr
/// @param attrs the list of attributes for the constant declaration. /// @param attrs the list of attributes for the constant declaration. If attributes are consumed
Maybe<const ast::Variable*> global_constant_decl(ast::AttributeList& attrs); /// by the declaration, then this vector is cleared before returning.
Maybe<const ast::Variable*> global_constant_decl(AttributeList& attrs);
/// Parses a `variable_decl` grammar element /// Parses a `variable_decl` grammar element
/// @returns the parsed variable declaration info /// @returns the parsed variable declaration info
Maybe<VarDeclInfo> variable_decl(); Maybe<VarDeclInfo> variable_decl();
@ -418,15 +431,16 @@ class ParserImpl {
Maybe<const ast::Struct*> struct_decl(); Maybe<const ast::Struct*> struct_decl();
/// Parses a `struct_body_decl` grammar element, erroring on parse failure. /// Parses a `struct_body_decl` grammar element, erroring on parse failure.
/// @returns the struct members /// @returns the struct members
Expect<ast::StructMemberList> expect_struct_body_decl(); Expect<StructMemberList> expect_struct_body_decl();
/// Parses a `struct_member` grammar element, erroring on parse failure. /// Parses a `struct_member` grammar element, erroring on parse failure.
/// @returns the struct member or nullptr /// @returns the struct member or nullptr
Expect<ast::StructMember*> expect_struct_member(); Expect<ast::StructMember*> expect_struct_member();
/// Parses a `function_decl` grammar element with the initial /// Parses a `function_decl` grammar element with the initial
/// `function_attribute_decl*` provided as `attrs`. /// `function_attribute_decl*` provided as `attrs`.
/// @param attrs the list of attributes for the function declaration. /// @param attrs the list of attributes for the function declaration. If attributes are consumed
/// by the declaration, then this vector is cleared before returning.
/// @returns the parsed function, nullptr otherwise /// @returns the parsed function, nullptr otherwise
Maybe<const ast::Function*> function_decl(ast::AttributeList& attrs); Maybe<const ast::Function*> function_decl(AttributeList& attrs);
/// Parses a `texture_samplers` grammar element /// Parses a `texture_samplers` grammar element
/// @returns the parsed Type or nullptr if none matched. /// @returns the parsed Type or nullptr if none matched.
Maybe<const ast::Type*> texture_samplers(); Maybe<const ast::Type*> texture_samplers();
@ -459,7 +473,7 @@ class ParserImpl {
Maybe<FunctionHeader> function_header(); Maybe<FunctionHeader> function_header();
/// Parses a `param_list` grammar element, erroring on parse failure. /// Parses a `param_list` grammar element, erroring on parse failure.
/// @returns the parsed variables /// @returns the parsed variables
Expect<ast::ParameterList> expect_param_list(); Expect<ParameterList> expect_param_list();
/// Parses a `param` grammar element, erroring on parse failure. /// Parses a `param` grammar element, erroring on parse failure.
/// @returns the parsed variable /// @returns the parsed variable
Expect<ast::Parameter*> expect_param(); Expect<ast::Parameter*> expect_param();
@ -484,7 +498,7 @@ class ParserImpl {
Expect<const ast::Expression*> expect_paren_expression(); Expect<const ast::Expression*> expect_paren_expression();
/// Parses a `statements` grammar element /// Parses a `statements` grammar element
/// @returns the statements parsed /// @returns the statements parsed
Expect<ast::StatementList> expect_statements(); Expect<StatementList> expect_statements();
/// Parses a `statement` grammar element /// Parses a `statement` grammar element
/// @returns the parsed statement or nullptr /// @returns the parsed statement or nullptr
Maybe<const ast::Statement*> statement(); Maybe<const ast::Statement*> statement();
@ -511,7 +525,7 @@ class ParserImpl {
Maybe<const ast::CaseStatement*> switch_body(); Maybe<const ast::CaseStatement*> switch_body();
/// Parses a `case_selectors` grammar element /// Parses a `case_selectors` grammar element
/// @returns the list of literals /// @returns the list of literals
Expect<ast::CaseSelectorList> expect_case_selectors(); Expect<CaseSelectorList> expect_case_selectors();
/// Parses a `case_body` grammar element /// Parses a `case_body` grammar element
/// @returns the parsed statements /// @returns the parsed statements
Maybe<const ast::BlockStatement*> case_body(); Maybe<const ast::BlockStatement*> case_body();
@ -543,7 +557,7 @@ class ParserImpl {
/// failure. /// failure.
/// @param use a description of what was being parsed if an error was raised /// @param use a description of what was being parsed if an error was raised
/// @returns the list of arguments /// @returns the list of arguments
Expect<ast::ExpressionList> expect_argument_expression_list(std::string_view use); Expect<ExpressionList> expect_argument_expression_list(std::string_view use);
/// Parses the recursive portion of the postfix_expression /// Parses the recursive portion of the postfix_expression
/// @param prefix the left side of the expression /// @param prefix the left side of the expression
/// @returns the parsed expression or nullptr /// @returns the parsed expression or nullptr
@ -642,7 +656,7 @@ class ParserImpl {
Maybe<const ast::Statement*> assignment_stmt(); Maybe<const ast::Statement*> assignment_stmt();
/// Parses one or more attribute lists. /// Parses one or more attribute lists.
/// @return the parsed attribute list, or an empty list on error. /// @return the parsed attribute list, or an empty list on error.
Maybe<ast::AttributeList> attribute_list(); Maybe<AttributeList> attribute_list();
/// Parses a single attribute of the following types: /// Parses a single attribute of the following types:
/// * `struct_attribute` /// * `struct_attribute`
/// * `struct_member_attribute` /// * `struct_member_attribute`
@ -813,7 +827,7 @@ class ParserImpl {
/// Reports an error if the attribute list `list` is not empty. /// Reports an error if the attribute list `list` is not empty.
/// Used to ensure that all attributes are consumed. /// Used to ensure that all attributes are consumed.
bool expect_attributes_consumed(ast::AttributeList& list); bool expect_attributes_consumed(utils::VectorRef<const ast::Attribute*> list);
Expect<const ast::Type*> expect_type_decl_pointer(const Token& t); Expect<const ast::Type*> expect_type_decl_pointer(const Token& t);
Expect<const ast::Type*> expect_type_decl_atomic(const Token& t); Expect<const ast::Type*> expect_type_decl_atomic(const Token& t);

View File

@ -23,7 +23,7 @@ TEST_F(ParserImplTest, ArgumentExpressionList_Parses) {
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(e.errored); ASSERT_FALSE(e.errored);
ASSERT_EQ(e.value.size(), 1u); ASSERT_EQ(e.value.Length(), 1u);
ASSERT_TRUE(e.value[0]->Is<ast::IdentifierExpression>()); ASSERT_TRUE(e.value[0]->Is<ast::IdentifierExpression>());
} }
@ -33,7 +33,7 @@ TEST_F(ParserImplTest, ArgumentExpressionList_ParsesEmptyList) {
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(e.errored); ASSERT_FALSE(e.errored);
ASSERT_EQ(e.value.size(), 0u); ASSERT_EQ(e.value.Length(), 0u);
} }
TEST_F(ParserImplTest, ArgumentExpressionList_ParsesMultiple) { TEST_F(ParserImplTest, ArgumentExpressionList_ParsesMultiple) {
@ -42,7 +42,7 @@ TEST_F(ParserImplTest, ArgumentExpressionList_ParsesMultiple) {
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(e.errored); ASSERT_FALSE(e.errored);
ASSERT_EQ(e.value.size(), 3u); ASSERT_EQ(e.value.Length(), 3u);
ASSERT_TRUE(e.value[0]->Is<ast::IdentifierExpression>()); ASSERT_TRUE(e.value[0]->Is<ast::IdentifierExpression>());
ASSERT_TRUE(e.value[1]->Is<ast::LiteralExpression>()); ASSERT_TRUE(e.value[1]->Is<ast::LiteralExpression>());
ASSERT_TRUE(e.value[2]->Is<ast::BinaryExpression>()); ASSERT_TRUE(e.value[2]->Is<ast::BinaryExpression>());
@ -54,7 +54,7 @@ TEST_F(ParserImplTest, ArgumentExpressionList_TrailingComma) {
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(e.errored); ASSERT_FALSE(e.errored);
ASSERT_EQ(e.value.size(), 2u); ASSERT_EQ(e.value.Length(), 2u);
ASSERT_TRUE(e.value[0]->Is<ast::IdentifierExpression>()); ASSERT_TRUE(e.value[0]->Is<ast::IdentifierExpression>());
ASSERT_TRUE(e.value[1]->Is<ast::LiteralExpression>()); ASSERT_TRUE(e.value[1]->Is<ast::LiteralExpression>());
} }

View File

@ -26,7 +26,7 @@ TEST_F(ParserImplTest, BodyStmt) {
auto e = p->expect_body_stmt(); auto e = p->expect_body_stmt();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(e.errored); ASSERT_FALSE(e.errored);
ASSERT_EQ(e->statements.size(), 2u); ASSERT_EQ(e->statements.Length(), 2u);
EXPECT_TRUE(e->statements[0]->Is<ast::DiscardStatement>()); EXPECT_TRUE(e->statements[0]->Is<ast::DiscardStatement>());
EXPECT_TRUE(e->statements[1]->Is<ast::ReturnStatement>()); EXPECT_TRUE(e->statements[1]->Is<ast::ReturnStatement>());
} }
@ -36,7 +36,7 @@ TEST_F(ParserImplTest, BodyStmt_Empty) {
auto e = p->expect_body_stmt(); auto e = p->expect_body_stmt();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(e.errored); ASSERT_FALSE(e.errored);
EXPECT_EQ(e->statements.size(), 0u); EXPECT_EQ(e->statements.Length(), 0u);
} }
TEST_F(ParserImplTest, BodyStmt_InvalidStmt) { TEST_F(ParserImplTest, BodyStmt_InvalidStmt) {

View File

@ -36,7 +36,7 @@ TEST_F(ParserImplTest, Statement_Call) {
EXPECT_EQ(c->target.name->symbol, p->builder().Symbols().Get("a")); EXPECT_EQ(c->target.name->symbol, p->builder().Symbols().Get("a"));
EXPECT_EQ(c->args.size(), 0u); EXPECT_EQ(c->args.Length(), 0u);
} }
TEST_F(ParserImplTest, Statement_Call_WithParams) { TEST_F(ParserImplTest, Statement_Call_WithParams) {
@ -52,7 +52,7 @@ TEST_F(ParserImplTest, Statement_Call_WithParams) {
EXPECT_EQ(c->target.name->symbol, p->builder().Symbols().Get("a")); EXPECT_EQ(c->target.name->symbol, p->builder().Symbols().Get("a"));
EXPECT_EQ(c->args.size(), 3u); EXPECT_EQ(c->args.Length(), 3u);
EXPECT_TRUE(c->args[0]->Is<ast::IntLiteralExpression>()); EXPECT_TRUE(c->args[0]->Is<ast::IntLiteralExpression>());
EXPECT_TRUE(c->args[1]->Is<ast::IdentifierExpression>()); EXPECT_TRUE(c->args[1]->Is<ast::IdentifierExpression>());
EXPECT_TRUE(c->args[2]->Is<ast::BinaryExpression>()); EXPECT_TRUE(c->args[2]->Is<ast::BinaryExpression>());
@ -71,7 +71,7 @@ TEST_F(ParserImplTest, Statement_Call_WithParams_TrailingComma) {
EXPECT_EQ(c->target.name->symbol, p->builder().Symbols().Get("a")); EXPECT_EQ(c->target.name->symbol, p->builder().Symbols().Get("a"));
EXPECT_EQ(c->args.size(), 2u); EXPECT_EQ(c->args.Length(), 2u);
EXPECT_TRUE(c->args[0]->Is<ast::IntLiteralExpression>()); EXPECT_TRUE(c->args[0]->Is<ast::IntLiteralExpression>());
EXPECT_TRUE(c->args[1]->Is<ast::IdentifierExpression>()); EXPECT_TRUE(c->args[1]->Is<ast::IdentifierExpression>());
} }

View File

@ -24,7 +24,7 @@ TEST_F(ParserImplTest, CaseBody_Empty) {
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(e.errored); EXPECT_FALSE(e.errored);
EXPECT_TRUE(e.matched); EXPECT_TRUE(e.matched);
EXPECT_EQ(e->statements.size(), 0u); EXPECT_EQ(e->statements.Length(), 0u);
} }
TEST_F(ParserImplTest, CaseBody_Statements) { TEST_F(ParserImplTest, CaseBody_Statements) {
@ -36,7 +36,7 @@ TEST_F(ParserImplTest, CaseBody_Statements) {
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(e.errored); EXPECT_FALSE(e.errored);
EXPECT_TRUE(e.matched); EXPECT_TRUE(e.matched);
ASSERT_EQ(e->statements.size(), 2u); ASSERT_EQ(e->statements.Length(), 2u);
EXPECT_TRUE(e->statements[0]->Is<ast::VariableDeclStatement>()); EXPECT_TRUE(e->statements[0]->Is<ast::VariableDeclStatement>());
EXPECT_TRUE(e->statements[1]->Is<ast::AssignmentStatement>()); EXPECT_TRUE(e->statements[1]->Is<ast::AssignmentStatement>());
} }
@ -56,7 +56,7 @@ TEST_F(ParserImplTest, CaseBody_Fallthrough) {
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(e.errored); EXPECT_FALSE(e.errored);
EXPECT_TRUE(e.matched); EXPECT_TRUE(e.matched);
ASSERT_EQ(e->statements.size(), 1u); ASSERT_EQ(e->statements.Length(), 1u);
EXPECT_TRUE(e->statements[0]->Is<ast::FallthroughStatement>()); EXPECT_TRUE(e->statements[0]->Is<ast::FallthroughStatement>());
} }

View File

@ -24,7 +24,7 @@ TEST_F(ParserImplTest, ContinuingStmt) {
EXPECT_TRUE(e.matched); EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e->statements.size(), 1u); ASSERT_EQ(e->statements.Length(), 1u);
ASSERT_TRUE(e->statements[0]->Is<ast::DiscardStatement>()); ASSERT_TRUE(e->statements[0]->Is<ast::DiscardStatement>());
} }

View File

@ -28,10 +28,10 @@ TEST_F(EnableDirectiveTest, Valid) {
EXPECT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(p->has_error()) << p->error();
auto program = p->program(); auto program = p->program();
auto& ast = program.AST(); auto& ast = program.AST();
ASSERT_EQ(ast.Enables().size(), 1u); ASSERT_EQ(ast.Enables().Length(), 1u);
auto* enable = ast.Enables()[0]; auto* enable = ast.Enables()[0];
EXPECT_EQ(enable->extension, ast::Extension::kF16); EXPECT_EQ(enable->extension, ast::Extension::kF16);
ASSERT_EQ(ast.GlobalDeclarations().size(), 1u); ASSERT_EQ(ast.GlobalDeclarations().Length(), 1u);
EXPECT_EQ(ast.GlobalDeclarations()[0], enable); EXPECT_EQ(ast.GlobalDeclarations()[0], enable);
} }
@ -45,12 +45,12 @@ enable f16;
EXPECT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(p->has_error()) << p->error();
auto program = p->program(); auto program = p->program();
auto& ast = program.AST(); auto& ast = program.AST();
ASSERT_EQ(ast.Enables().size(), 2u); ASSERT_EQ(ast.Enables().Length(), 2u);
auto* enable_a = ast.Enables()[0]; auto* enable_a = ast.Enables()[0];
auto* enable_b = ast.Enables()[1]; auto* enable_b = ast.Enables()[1];
EXPECT_EQ(enable_a->extension, ast::Extension::kF16); EXPECT_EQ(enable_a->extension, ast::Extension::kF16);
EXPECT_EQ(enable_b->extension, ast::Extension::kF16); EXPECT_EQ(enable_b->extension, ast::Extension::kF16);
ASSERT_EQ(ast.GlobalDeclarations().size(), 2u); ASSERT_EQ(ast.GlobalDeclarations().Length(), 2u);
EXPECT_EQ(ast.GlobalDeclarations()[0], enable_a); EXPECT_EQ(ast.GlobalDeclarations()[0], enable_a);
EXPECT_EQ(ast.GlobalDeclarations()[1], enable_b); EXPECT_EQ(ast.GlobalDeclarations()[1], enable_b);
} }
@ -64,8 +64,8 @@ TEST_F(EnableDirectiveTest, InvalidIdentifier) {
EXPECT_EQ(p->error(), "1:8: unsupported extension: 'NotAValidExtensionName'"); EXPECT_EQ(p->error(), "1:8: unsupported extension: 'NotAValidExtensionName'");
auto program = p->program(); auto program = p->program();
auto& ast = program.AST(); auto& ast = program.AST();
EXPECT_EQ(ast.Enables().size(), 0u); EXPECT_EQ(ast.Enables().Length(), 0u);
EXPECT_EQ(ast.GlobalDeclarations().size(), 0u); EXPECT_EQ(ast.GlobalDeclarations().Length(), 0u);
} }
// Test an enable directive missing ending semicolon. // Test an enable directive missing ending semicolon.
@ -76,8 +76,8 @@ TEST_F(EnableDirectiveTest, MissingEndingSemicolon) {
EXPECT_EQ(p->error(), "1:11: expected ';' for enable directive"); EXPECT_EQ(p->error(), "1:11: expected ';' for enable directive");
auto program = p->program(); auto program = p->program();
auto& ast = program.AST(); auto& ast = program.AST();
EXPECT_EQ(ast.Enables().size(), 0u); EXPECT_EQ(ast.Enables().Length(), 0u);
EXPECT_EQ(ast.GlobalDeclarations().size(), 0u); EXPECT_EQ(ast.GlobalDeclarations().Length(), 0u);
} }
// Test the special error message when enable are used with parenthesis. // Test the special error message when enable are used with parenthesis.
@ -88,8 +88,8 @@ TEST_F(EnableDirectiveTest, ParenthesisSpecialCase) {
EXPECT_EQ(p->error(), "1:7: enable directives don't take parenthesis"); EXPECT_EQ(p->error(), "1:7: enable directives don't take parenthesis");
auto program = p->program(); auto program = p->program();
auto& ast = program.AST(); auto& ast = program.AST();
EXPECT_EQ(ast.Enables().size(), 0u); EXPECT_EQ(ast.Enables().Length(), 0u);
EXPECT_EQ(ast.GlobalDeclarations().size(), 0u); EXPECT_EQ(ast.GlobalDeclarations().Length(), 0u);
} }
// Test using invalid tokens in an enable directive. // Test using invalid tokens in an enable directive.
@ -101,8 +101,8 @@ TEST_F(EnableDirectiveTest, InvalidTokens) {
EXPECT_EQ(p->error(), "1:11: expected ';' for enable directive"); EXPECT_EQ(p->error(), "1:11: expected ';' for enable directive");
auto program = p->program(); auto program = p->program();
auto& ast = program.AST(); auto& ast = program.AST();
EXPECT_EQ(ast.Enables().size(), 0u); EXPECT_EQ(ast.Enables().Length(), 0u);
EXPECT_EQ(ast.GlobalDeclarations().size(), 0u); EXPECT_EQ(ast.GlobalDeclarations().Length(), 0u);
} }
{ {
auto p = parser("enable <f16;"); auto p = parser("enable <f16;");
@ -111,8 +111,8 @@ TEST_F(EnableDirectiveTest, InvalidTokens) {
EXPECT_EQ(p->error(), "1:8: invalid extension name"); EXPECT_EQ(p->error(), "1:8: invalid extension name");
auto program = p->program(); auto program = p->program();
auto& ast = program.AST(); auto& ast = program.AST();
EXPECT_EQ(ast.Enables().size(), 0u); EXPECT_EQ(ast.Enables().Length(), 0u);
EXPECT_EQ(ast.GlobalDeclarations().size(), 0u); EXPECT_EQ(ast.GlobalDeclarations().Length(), 0u);
} }
{ {
auto p = parser("enable =;"); auto p = parser("enable =;");
@ -121,8 +121,8 @@ TEST_F(EnableDirectiveTest, InvalidTokens) {
EXPECT_EQ(p->error(), "1:8: invalid extension name"); EXPECT_EQ(p->error(), "1:8: invalid extension name");
auto program = p->program(); auto program = p->program();
auto& ast = program.AST(); auto& ast = program.AST();
EXPECT_EQ(ast.Enables().size(), 0u); EXPECT_EQ(ast.Enables().Length(), 0u);
EXPECT_EQ(ast.GlobalDeclarations().size(), 0u); EXPECT_EQ(ast.GlobalDeclarations().Length(), 0u);
} }
{ {
auto p = parser("enable vec4;"); auto p = parser("enable vec4;");
@ -131,8 +131,8 @@ TEST_F(EnableDirectiveTest, InvalidTokens) {
EXPECT_EQ(p->error(), "1:8: invalid extension name"); EXPECT_EQ(p->error(), "1:8: invalid extension name");
auto program = p->program(); auto program = p->program();
auto& ast = program.AST(); auto& ast = program.AST();
EXPECT_EQ(ast.Enables().size(), 0u); EXPECT_EQ(ast.Enables().Length(), 0u);
EXPECT_EQ(ast.GlobalDeclarations().size(), 0u); EXPECT_EQ(ast.GlobalDeclarations().Length(), 0u);
} }
} }
@ -148,10 +148,10 @@ enable f16;
auto program = p->program(); auto program = p->program();
auto& ast = program.AST(); auto& ast = program.AST();
// Accept the enable directive although it caused an error // Accept the enable directive although it caused an error
ASSERT_EQ(ast.Enables().size(), 1u); ASSERT_EQ(ast.Enables().Length(), 1u);
auto* enable = ast.Enables()[0]; auto* enable = ast.Enables()[0];
EXPECT_EQ(enable->extension, ast::Extension::kF16); EXPECT_EQ(enable->extension, ast::Extension::kF16);
ASSERT_EQ(ast.GlobalDeclarations().size(), 2u); ASSERT_EQ(ast.GlobalDeclarations().Length(), 2u);
EXPECT_EQ(ast.GlobalDeclarations()[1], enable); EXPECT_EQ(ast.GlobalDeclarations()[1], enable);
} }
@ -168,10 +168,10 @@ enable f16;
auto program = p->program(); auto program = p->program();
auto& ast = program.AST(); auto& ast = program.AST();
// Accept the enable directive although it cause an error // Accept the enable directive although it cause an error
ASSERT_EQ(ast.Enables().size(), 1u); ASSERT_EQ(ast.Enables().Length(), 1u);
auto* enable = ast.Enables()[0]; auto* enable = ast.Enables()[0];
EXPECT_EQ(enable->extension, ast::Extension::kF16); EXPECT_EQ(enable->extension, ast::Extension::kF16);
ASSERT_EQ(ast.GlobalDeclarations().size(), 1u); ASSERT_EQ(ast.GlobalDeclarations().Length(), 1u);
EXPECT_EQ(ast.GlobalDeclarations()[0], enable); EXPECT_EQ(ast.GlobalDeclarations()[0], enable);
} }

View File

@ -44,7 +44,7 @@ TEST_F(ForStmtTest, Body) {
EXPECT_EQ(fl->initializer, nullptr); EXPECT_EQ(fl->initializer, nullptr);
EXPECT_EQ(fl->condition, nullptr); EXPECT_EQ(fl->condition, nullptr);
EXPECT_EQ(fl->continuing, nullptr); EXPECT_EQ(fl->continuing, nullptr);
ASSERT_EQ(fl->body->statements.size(), 1u); ASSERT_EQ(fl->body->statements.Length(), 1u);
EXPECT_TRUE(fl->body->statements[0]->Is<ast::DiscardStatement>()); EXPECT_TRUE(fl->body->statements[0]->Is<ast::DiscardStatement>());
} }

View File

@ -25,7 +25,7 @@ TEST_F(ParserImplTest, AttributeList_Parses_Stage) {
EXPECT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(attrs.errored); EXPECT_FALSE(attrs.errored);
EXPECT_TRUE(attrs.matched); EXPECT_TRUE(attrs.matched);
ASSERT_EQ(attrs.value.size(), 2u); ASSERT_EQ(attrs.value.Length(), 2u);
auto* attr_0 = attrs.value[0]->As<ast::Attribute>(); auto* attr_0 = attrs.value[0]->As<ast::Attribute>();
auto* attr_1 = attrs.value[1]->As<ast::Attribute>(); auto* attr_1 = attrs.value[1]->As<ast::Attribute>();
@ -51,7 +51,7 @@ TEST_F(ParserImplTest, AttributeList_Parses) {
EXPECT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(attrs.errored); EXPECT_FALSE(attrs.errored);
EXPECT_TRUE(attrs.matched); EXPECT_TRUE(attrs.matched);
ASSERT_EQ(attrs.value.size(), 2u); ASSERT_EQ(attrs.value.Length(), 2u);
auto* attr_0 = attrs.value[0]->As<ast::Attribute>(); auto* attr_0 = attrs.value[0]->As<ast::Attribute>();
auto* attr_1 = attrs.value[1]->As<ast::Attribute>(); auto* attr_1 = attrs.value[1]->As<ast::Attribute>();
@ -77,7 +77,7 @@ TEST_F(ParserImplTest, AttributeList_Invalid) {
EXPECT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
EXPECT_TRUE(attrs.errored); EXPECT_TRUE(attrs.errored);
EXPECT_FALSE(attrs.matched); EXPECT_FALSE(attrs.matched);
EXPECT_TRUE(attrs.value.empty()); EXPECT_TRUE(attrs.value.IsEmpty());
EXPECT_EQ(p->error(), "1:2: expected attribute"); EXPECT_EQ(p->error(), "1:2: expected attribute");
} }

View File

@ -35,7 +35,7 @@ TEST_F(ParserImplTest, FunctionDecl) {
ASSERT_NE(f->return_type, nullptr); ASSERT_NE(f->return_type, nullptr);
EXPECT_TRUE(f->return_type->Is<ast::Void>()); EXPECT_TRUE(f->return_type->Is<ast::Void>());
ASSERT_EQ(f->params.size(), 2u); ASSERT_EQ(f->params.Length(), 2u);
EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get("a")); EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get("a"));
EXPECT_EQ(f->params[1]->symbol, p->builder().Symbols().Get("b")); EXPECT_EQ(f->params[1]->symbol, p->builder().Symbols().Get("b"));
@ -43,7 +43,7 @@ TEST_F(ParserImplTest, FunctionDecl) {
EXPECT_TRUE(f->return_type->Is<ast::Void>()); EXPECT_TRUE(f->return_type->Is<ast::Void>());
auto* body = f->body; auto* body = f->body;
ASSERT_EQ(body->statements.size(), 1u); ASSERT_EQ(body->statements.Length(), 1u);
EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>()); EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>());
} }
@ -80,7 +80,7 @@ TEST_F(ParserImplTest, FunctionDecl_Unicode) {
ASSERT_NE(f->return_type, nullptr); ASSERT_NE(f->return_type, nullptr);
EXPECT_TRUE(f->return_type->Is<ast::Void>()); EXPECT_TRUE(f->return_type->Is<ast::Void>());
ASSERT_EQ(f->params.size(), 2u); ASSERT_EQ(f->params.Length(), 2u);
EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get(param_a_ident)); EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get(param_a_ident));
EXPECT_EQ(f->params[1]->symbol, p->builder().Symbols().Get(param_b_ident)); EXPECT_EQ(f->params[1]->symbol, p->builder().Symbols().Get(param_b_ident));
@ -88,7 +88,7 @@ TEST_F(ParserImplTest, FunctionDecl_Unicode) {
EXPECT_TRUE(f->return_type->Is<ast::Void>()); EXPECT_TRUE(f->return_type->Is<ast::Void>());
auto* body = f->body; auto* body = f->body;
ASSERT_EQ(body->statements.size(), 1u); ASSERT_EQ(body->statements.Length(), 1u);
EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>()); EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>());
} }
@ -107,10 +107,10 @@ TEST_F(ParserImplTest, FunctionDecl_AttributeList) {
EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main")); EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main"));
ASSERT_NE(f->return_type, nullptr); ASSERT_NE(f->return_type, nullptr);
EXPECT_TRUE(f->return_type->Is<ast::Void>()); EXPECT_TRUE(f->return_type->Is<ast::Void>());
ASSERT_EQ(f->params.size(), 0u); ASSERT_EQ(f->params.Length(), 0u);
auto& attributes = f->attributes; auto& attributes = f->attributes;
ASSERT_EQ(attributes.size(), 1u); ASSERT_EQ(attributes.Length(), 1u);
ASSERT_TRUE(attributes[0]->Is<ast::WorkgroupAttribute>()); ASSERT_TRUE(attributes[0]->Is<ast::WorkgroupAttribute>());
auto values = attributes[0]->As<ast::WorkgroupAttribute>()->Values(); auto values = attributes[0]->As<ast::WorkgroupAttribute>()->Values();
@ -131,7 +131,7 @@ TEST_F(ParserImplTest, FunctionDecl_AttributeList) {
ast::IntLiteralExpression::Suffix::kNone); ast::IntLiteralExpression::Suffix::kNone);
auto* body = f->body; auto* body = f->body;
ASSERT_EQ(body->statements.size(), 1u); ASSERT_EQ(body->statements.Length(), 1u);
EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>()); EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>());
} }
@ -152,10 +152,10 @@ fn main() { return; })");
EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main")); EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main"));
ASSERT_NE(f->return_type, nullptr); ASSERT_NE(f->return_type, nullptr);
EXPECT_TRUE(f->return_type->Is<ast::Void>()); EXPECT_TRUE(f->return_type->Is<ast::Void>());
ASSERT_EQ(f->params.size(), 0u); ASSERT_EQ(f->params.Length(), 0u);
auto& attributes = f->attributes; auto& attributes = f->attributes;
ASSERT_EQ(attributes.size(), 2u); ASSERT_EQ(attributes.Length(), 2u);
ASSERT_TRUE(attributes[0]->Is<ast::WorkgroupAttribute>()); ASSERT_TRUE(attributes[0]->Is<ast::WorkgroupAttribute>());
auto values = attributes[0]->As<ast::WorkgroupAttribute>()->Values(); auto values = attributes[0]->As<ast::WorkgroupAttribute>()->Values();
@ -179,7 +179,7 @@ fn main() { return; })");
EXPECT_EQ(attributes[1]->As<ast::StageAttribute>()->stage, ast::PipelineStage::kCompute); EXPECT_EQ(attributes[1]->As<ast::StageAttribute>()->stage, ast::PipelineStage::kCompute);
auto* body = f->body; auto* body = f->body;
ASSERT_EQ(body->statements.size(), 1u); ASSERT_EQ(body->statements.Length(), 1u);
EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>()); EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>());
} }
@ -201,10 +201,10 @@ fn main() { return; })");
EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main")); EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main"));
ASSERT_NE(f->return_type, nullptr); ASSERT_NE(f->return_type, nullptr);
EXPECT_TRUE(f->return_type->Is<ast::Void>()); EXPECT_TRUE(f->return_type->Is<ast::Void>());
ASSERT_EQ(f->params.size(), 0u); ASSERT_EQ(f->params.Length(), 0u);
auto& attrs = f->attributes; auto& attrs = f->attributes;
ASSERT_EQ(attrs.size(), 2u); ASSERT_EQ(attrs.Length(), 2u);
ASSERT_TRUE(attrs[0]->Is<ast::WorkgroupAttribute>()); ASSERT_TRUE(attrs[0]->Is<ast::WorkgroupAttribute>());
auto values = attrs[0]->As<ast::WorkgroupAttribute>()->Values(); auto values = attrs[0]->As<ast::WorkgroupAttribute>()->Values();
@ -228,7 +228,7 @@ fn main() { return; })");
EXPECT_EQ(attrs[1]->As<ast::StageAttribute>()->stage, ast::PipelineStage::kCompute); EXPECT_EQ(attrs[1]->As<ast::StageAttribute>()->stage, ast::PipelineStage::kCompute);
auto* body = f->body; auto* body = f->body;
ASSERT_EQ(body->statements.size(), 1u); ASSERT_EQ(body->statements.Length(), 1u);
EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>()); EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>());
} }
@ -247,19 +247,19 @@ TEST_F(ParserImplTest, FunctionDecl_ReturnTypeAttributeList) {
EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main")); EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main"));
ASSERT_NE(f->return_type, nullptr); ASSERT_NE(f->return_type, nullptr);
EXPECT_TRUE(f->return_type->Is<ast::F32>()); EXPECT_TRUE(f->return_type->Is<ast::F32>());
ASSERT_EQ(f->params.size(), 0u); ASSERT_EQ(f->params.Length(), 0u);
auto& attributes = f->attributes; auto& attributes = f->attributes;
EXPECT_EQ(attributes.size(), 0u); EXPECT_EQ(attributes.Length(), 0u);
auto& ret_type_attributes = f->return_type_attributes; auto& ret_type_attributes = f->return_type_attributes;
ASSERT_EQ(ret_type_attributes.size(), 1u); ASSERT_EQ(ret_type_attributes.Length(), 1u);
auto* loc = ret_type_attributes[0]->As<ast::LocationAttribute>(); auto* loc = ret_type_attributes[0]->As<ast::LocationAttribute>();
ASSERT_TRUE(loc != nullptr); ASSERT_TRUE(loc != nullptr);
EXPECT_EQ(loc->value, 1u); EXPECT_EQ(loc->value, 1u);
auto* body = f->body; auto* body = f->body;
ASSERT_EQ(body->statements.size(), 1u); ASSERT_EQ(body->statements.Length(), 1u);
EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>()); EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>());
} }

View File

@ -25,7 +25,7 @@ TEST_F(ParserImplTest, FunctionHeader) {
EXPECT_FALSE(f.errored); EXPECT_FALSE(f.errored);
EXPECT_EQ(f->name, "main"); EXPECT_EQ(f->name, "main");
ASSERT_EQ(f->params.size(), 2u); ASSERT_EQ(f->params.Length(), 2u);
EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get("a")); EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get("a"));
EXPECT_EQ(f->params[1]->symbol, p->builder().Symbols().Get("b")); EXPECT_EQ(f->params[1]->symbol, p->builder().Symbols().Get("b"));
EXPECT_TRUE(f->return_type->Is<ast::Void>()); EXPECT_TRUE(f->return_type->Is<ast::Void>());
@ -38,7 +38,7 @@ TEST_F(ParserImplTest, FunctionHeader_TrailingComma) {
EXPECT_FALSE(f.errored); EXPECT_FALSE(f.errored);
EXPECT_EQ(f->name, "main"); EXPECT_EQ(f->name, "main");
ASSERT_EQ(f->params.size(), 1u); ASSERT_EQ(f->params.Length(), 1u);
EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get("a")); EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get("a"));
EXPECT_TRUE(f->return_type->Is<ast::Void>()); EXPECT_TRUE(f->return_type->Is<ast::Void>());
} }
@ -51,9 +51,9 @@ TEST_F(ParserImplTest, FunctionHeader_AttributeReturnType) {
EXPECT_FALSE(f.errored); EXPECT_FALSE(f.errored);
EXPECT_EQ(f->name, "main"); EXPECT_EQ(f->name, "main");
EXPECT_EQ(f->params.size(), 0u); EXPECT_EQ(f->params.Length(), 0u);
EXPECT_TRUE(f->return_type->Is<ast::F32>()); EXPECT_TRUE(f->return_type->Is<ast::F32>());
ASSERT_EQ(f->return_type_attributes.size(), 1u); ASSERT_EQ(f->return_type_attributes.Length(), 1u);
auto* loc = f->return_type_attributes[0]->As<ast::LocationAttribute>(); auto* loc = f->return_type_attributes[0]->As<ast::LocationAttribute>();
ASSERT_TRUE(loc != nullptr); ASSERT_TRUE(loc != nullptr);
EXPECT_EQ(loc->value, 1u); EXPECT_EQ(loc->value, 1u);
@ -67,9 +67,9 @@ TEST_F(ParserImplTest, FunctionHeader_InvariantReturnType) {
EXPECT_FALSE(f.errored); EXPECT_FALSE(f.errored);
EXPECT_EQ(f->name, "main"); EXPECT_EQ(f->name, "main");
EXPECT_EQ(f->params.size(), 0u); EXPECT_EQ(f->params.Length(), 0u);
EXPECT_TRUE(f->return_type->Is<ast::F32>()); EXPECT_TRUE(f->return_type->Is<ast::F32>());
ASSERT_EQ(f->return_type_attributes.size(), 1u); ASSERT_EQ(f->return_type_attributes.Length(), 1u);
EXPECT_TRUE(f->return_type_attributes[0]->Is<ast::InvariantAttribute>()); EXPECT_TRUE(f->return_type_attributes[0]->Is<ast::InvariantAttribute>());
} }

View File

@ -29,7 +29,7 @@ TEST_F(ParserImplTest, GlobalDecl_GlobalVariable) {
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
auto program = p->program(); auto program = p->program();
ASSERT_EQ(program.AST().GlobalVariables().size(), 1u); ASSERT_EQ(program.AST().GlobalVariables().Length(), 1u);
auto* v = program.AST().GlobalVariables()[0]; auto* v = program.AST().GlobalVariables()[0];
EXPECT_EQ(v->symbol, program.Symbols().Get("a")); EXPECT_EQ(v->symbol, program.Symbols().Get("a"));
@ -42,7 +42,7 @@ TEST_F(ParserImplTest, GlobalDecl_GlobalVariable_Inferred) {
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
auto program = p->program(); auto program = p->program();
ASSERT_EQ(program.AST().GlobalVariables().size(), 1u); ASSERT_EQ(program.AST().GlobalVariables().Length(), 1u);
auto* v = program.AST().GlobalVariables()[0]; auto* v = program.AST().GlobalVariables()[0];
EXPECT_EQ(v->symbol, program.Symbols().Get("a")); EXPECT_EQ(v->symbol, program.Symbols().Get("a"));
@ -62,7 +62,7 @@ TEST_F(ParserImplTest, GlobalDecl_GlobalLet) {
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
auto program = p->program(); auto program = p->program();
ASSERT_EQ(program.AST().GlobalVariables().size(), 1u); ASSERT_EQ(program.AST().GlobalVariables().Length(), 1u);
auto* v = program.AST().GlobalVariables()[0]; auto* v = program.AST().GlobalVariables()[0];
EXPECT_EQ(v->symbol, program.Symbols().Get("a")); EXPECT_EQ(v->symbol, program.Symbols().Get("a"));
@ -104,7 +104,7 @@ TEST_F(ParserImplTest, GlobalDecl_GlobalConst) {
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
auto program = p->program(); auto program = p->program();
ASSERT_EQ(program.AST().GlobalVariables().size(), 1u); ASSERT_EQ(program.AST().GlobalVariables().Length(), 1u);
auto* v = program.AST().GlobalVariables()[0]; auto* v = program.AST().GlobalVariables()[0];
EXPECT_EQ(v->symbol, program.Symbols().Get("a")); EXPECT_EQ(v->symbol, program.Symbols().Get("a"));
@ -137,7 +137,7 @@ TEST_F(ParserImplTest, GlobalDecl_TypeAlias) {
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
auto program = p->program(); auto program = p->program();
ASSERT_EQ(program.AST().TypeDecls().size(), 1u); ASSERT_EQ(program.AST().TypeDecls().Length(), 1u);
ASSERT_TRUE(program.AST().TypeDecls()[0]->Is<ast::Alias>()); ASSERT_TRUE(program.AST().TypeDecls()[0]->Is<ast::Alias>());
EXPECT_EQ(program.Symbols().NameFor(program.AST().TypeDecls()[0]->As<ast::Alias>()->name), "A"); EXPECT_EQ(program.Symbols().NameFor(program.AST().TypeDecls()[0]->As<ast::Alias>()->name), "A");
} }
@ -152,7 +152,7 @@ type B = A;)");
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
auto program = p->program(); auto program = p->program();
ASSERT_EQ(program.AST().TypeDecls().size(), 2u); ASSERT_EQ(program.AST().TypeDecls().Length(), 2u);
ASSERT_TRUE(program.AST().TypeDecls()[0]->Is<ast::Struct>()); ASSERT_TRUE(program.AST().TypeDecls()[0]->Is<ast::Struct>());
auto* str = program.AST().TypeDecls()[0]->As<ast::Struct>(); auto* str = program.AST().TypeDecls()[0]->As<ast::Struct>();
EXPECT_EQ(str->name, program.Symbols().Get("A")); EXPECT_EQ(str->name, program.Symbols().Get("A"));
@ -178,7 +178,7 @@ TEST_F(ParserImplTest, GlobalDecl_Function) {
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
auto program = p->program(); auto program = p->program();
ASSERT_EQ(program.AST().Functions().size(), 1u); ASSERT_EQ(program.AST().Functions().Length(), 1u);
EXPECT_EQ(program.Symbols().NameFor(program.AST().Functions()[0]->symbol), "main"); EXPECT_EQ(program.Symbols().NameFor(program.AST().Functions()[0]->symbol), "main");
} }
@ -188,7 +188,7 @@ TEST_F(ParserImplTest, GlobalDecl_Function_WithAttribute) {
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
auto program = p->program(); auto program = p->program();
ASSERT_EQ(program.AST().Functions().size(), 1u); ASSERT_EQ(program.AST().Functions().Length(), 1u);
EXPECT_EQ(program.Symbols().NameFor(program.AST().Functions()[0]->symbol), "main"); EXPECT_EQ(program.Symbols().NameFor(program.AST().Functions()[0]->symbol), "main");
} }
@ -205,7 +205,7 @@ TEST_F(ParserImplTest, GlobalDecl_ParsesStruct) {
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
auto program = p->program(); auto program = p->program();
ASSERT_EQ(program.AST().TypeDecls().size(), 1u); ASSERT_EQ(program.AST().TypeDecls().Length(), 1u);
auto* t = program.AST().TypeDecls()[0]; auto* t = program.AST().TypeDecls()[0];
ASSERT_NE(t, nullptr); ASSERT_NE(t, nullptr);
@ -213,7 +213,7 @@ TEST_F(ParserImplTest, GlobalDecl_ParsesStruct) {
auto* str = t->As<ast::Struct>(); auto* str = t->As<ast::Struct>();
EXPECT_EQ(str->name, program.Symbols().Get("A")); EXPECT_EQ(str->name, program.Symbols().Get("A"));
EXPECT_EQ(str->members.size(), 2u); EXPECT_EQ(str->members.Length(), 2u);
} }
TEST_F(ParserImplTest, GlobalDecl_Struct_Invalid) { TEST_F(ParserImplTest, GlobalDecl_Struct_Invalid) {

View File

@ -91,7 +91,7 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithAttribute) {
ASSERT_EQ(var->constructor, nullptr); ASSERT_EQ(var->constructor, nullptr);
auto& attributes = var->attributes; auto& attributes = var->attributes;
ASSERT_EQ(attributes.size(), 2u); ASSERT_EQ(attributes.Length(), 2u);
ASSERT_TRUE(attributes[0]->Is<ast::BindingAttribute>()); ASSERT_TRUE(attributes[0]->Is<ast::BindingAttribute>());
ASSERT_TRUE(attributes[1]->Is<ast::GroupAttribute>()); ASSERT_TRUE(attributes[1]->Is<ast::GroupAttribute>());
} }
@ -122,7 +122,7 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithAttribute_MulitpleGroups) {
ASSERT_EQ(var->constructor, nullptr); ASSERT_EQ(var->constructor, nullptr);
auto& attributes = var->attributes; auto& attributes = var->attributes;
ASSERT_EQ(attributes.size(), 2u); ASSERT_EQ(attributes.Length(), 2u);
ASSERT_TRUE(attributes[0]->Is<ast::BindingAttribute>()); ASSERT_TRUE(attributes[0]->Is<ast::BindingAttribute>());
ASSERT_TRUE(attributes[1]->Is<ast::GroupAttribute>()); ASSERT_TRUE(attributes[1]->Is<ast::GroupAttribute>());
} }
@ -152,7 +152,7 @@ TEST_F(ParserImplTest, GlobalVariableDecl_InvalidConstExpr) {
EXPECT_TRUE(e.errored); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched); EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr); EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:24: missing initalizer for 'var' declaration"); EXPECT_EQ(p->error(), "1:24: missing initializer for 'var' declaration");
} }
TEST_F(ParserImplTest, GlobalVariableDecl_InvalidVariableDecl) { TEST_F(ParserImplTest, GlobalVariableDecl_InvalidVariableDecl) {

View File

@ -28,7 +28,7 @@ TEST_F(ParserImplTest, IfStmt) {
ASSERT_TRUE(e->Is<ast::IfStatement>()); ASSERT_TRUE(e->Is<ast::IfStatement>());
ASSERT_NE(e->condition, nullptr); ASSERT_NE(e->condition, nullptr);
ASSERT_TRUE(e->condition->Is<ast::BinaryExpression>()); ASSERT_TRUE(e->condition->Is<ast::BinaryExpression>());
EXPECT_EQ(e->body->statements.size(), 2u); EXPECT_EQ(e->body->statements.Length(), 2u);
EXPECT_EQ(e->else_statement, nullptr); EXPECT_EQ(e->else_statement, nullptr);
} }
@ -43,16 +43,16 @@ TEST_F(ParserImplTest, IfStmt_WithElse) {
ASSERT_TRUE(e->Is<ast::IfStatement>()); ASSERT_TRUE(e->Is<ast::IfStatement>());
ASSERT_NE(e->condition, nullptr); ASSERT_NE(e->condition, nullptr);
ASSERT_TRUE(e->condition->Is<ast::BinaryExpression>()); ASSERT_TRUE(e->condition->Is<ast::BinaryExpression>());
EXPECT_EQ(e->body->statements.size(), 2u); EXPECT_EQ(e->body->statements.Length(), 2u);
auto* elseif = As<ast::IfStatement>(e->else_statement); auto* elseif = As<ast::IfStatement>(e->else_statement);
ASSERT_NE(elseif, nullptr); ASSERT_NE(elseif, nullptr);
ASSERT_TRUE(elseif->condition->Is<ast::IdentifierExpression>()); ASSERT_TRUE(elseif->condition->Is<ast::IdentifierExpression>());
EXPECT_EQ(elseif->body->statements.size(), 1u); EXPECT_EQ(elseif->body->statements.Length(), 1u);
auto* el = As<ast::BlockStatement>(elseif->else_statement); auto* el = As<ast::BlockStatement>(elseif->else_statement);
ASSERT_NE(el, nullptr); ASSERT_NE(el, nullptr);
EXPECT_EQ(el->statements.size(), 0u); EXPECT_EQ(el->statements.Length(), 0u);
} }
TEST_F(ParserImplTest, IfStmt_WithElse_WithParens) { TEST_F(ParserImplTest, IfStmt_WithElse_WithParens) {
@ -66,16 +66,16 @@ TEST_F(ParserImplTest, IfStmt_WithElse_WithParens) {
ASSERT_TRUE(e->Is<ast::IfStatement>()); ASSERT_TRUE(e->Is<ast::IfStatement>());
ASSERT_NE(e->condition, nullptr); ASSERT_NE(e->condition, nullptr);
ASSERT_TRUE(e->condition->Is<ast::BinaryExpression>()); ASSERT_TRUE(e->condition->Is<ast::BinaryExpression>());
EXPECT_EQ(e->body->statements.size(), 2u); EXPECT_EQ(e->body->statements.Length(), 2u);
auto* elseif = As<ast::IfStatement>(e->else_statement); auto* elseif = As<ast::IfStatement>(e->else_statement);
ASSERT_NE(elseif, nullptr); ASSERT_NE(elseif, nullptr);
ASSERT_TRUE(elseif->condition->Is<ast::IdentifierExpression>()); ASSERT_TRUE(elseif->condition->Is<ast::IdentifierExpression>());
EXPECT_EQ(elseif->body->statements.size(), 1u); EXPECT_EQ(elseif->body->statements.Length(), 1u);
auto* el = As<ast::BlockStatement>(elseif->else_statement); auto* el = As<ast::BlockStatement>(elseif->else_statement);
ASSERT_NE(el, nullptr); ASSERT_NE(el, nullptr);
EXPECT_EQ(el->statements.size(), 0u); EXPECT_EQ(el->statements.Length(), 0u);
} }
TEST_F(ParserImplTest, IfStmt_InvalidCondition) { TEST_F(ParserImplTest, IfStmt_InvalidCondition) {

View File

@ -26,10 +26,10 @@ TEST_F(ParserImplTest, LoopStmt_BodyNoContinuing) {
EXPECT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr); ASSERT_NE(e.value, nullptr);
ASSERT_EQ(e->body->statements.size(), 1u); ASSERT_EQ(e->body->statements.Length(), 1u);
EXPECT_TRUE(e->body->statements[0]->Is<ast::DiscardStatement>()); EXPECT_TRUE(e->body->statements[0]->Is<ast::DiscardStatement>());
EXPECT_EQ(e->continuing->statements.size(), 0u); EXPECT_EQ(e->continuing->statements.Length(), 0u);
} }
TEST_F(ParserImplTest, LoopStmt_BodyWithContinuing) { TEST_F(ParserImplTest, LoopStmt_BodyWithContinuing) {
@ -40,10 +40,10 @@ TEST_F(ParserImplTest, LoopStmt_BodyWithContinuing) {
EXPECT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr); ASSERT_NE(e.value, nullptr);
ASSERT_EQ(e->body->statements.size(), 1u); ASSERT_EQ(e->body->statements.Length(), 1u);
EXPECT_TRUE(e->body->statements[0]->Is<ast::DiscardStatement>()); EXPECT_TRUE(e->body->statements[0]->Is<ast::DiscardStatement>());
EXPECT_EQ(e->continuing->statements.size(), 1u); EXPECT_EQ(e->continuing->statements.Length(), 1u);
EXPECT_TRUE(e->continuing->statements[0]->Is<ast::DiscardStatement>()); EXPECT_TRUE(e->continuing->statements[0]->Is<ast::DiscardStatement>());
} }
@ -54,8 +54,8 @@ TEST_F(ParserImplTest, LoopStmt_NoBodyNoContinuing) {
EXPECT_FALSE(e.errored); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr); ASSERT_NE(e.value, nullptr);
ASSERT_EQ(e->body->statements.size(), 0u); ASSERT_EQ(e->body->statements.Length(), 0u);
ASSERT_EQ(e->continuing->statements.size(), 0u); ASSERT_EQ(e->continuing->statements.Length(), 0u);
} }
TEST_F(ParserImplTest, LoopStmt_NoBodyWithContinuing) { TEST_F(ParserImplTest, LoopStmt_NoBodyWithContinuing) {
@ -65,8 +65,8 @@ TEST_F(ParserImplTest, LoopStmt_NoBodyWithContinuing) {
EXPECT_FALSE(e.errored); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr); ASSERT_NE(e.value, nullptr);
ASSERT_EQ(e->body->statements.size(), 0u); ASSERT_EQ(e->body->statements.Length(), 0u);
ASSERT_EQ(e->continuing->statements.size(), 1u); ASSERT_EQ(e->continuing->statements.Length(), 1u);
EXPECT_TRUE(e->continuing->statements[0]->Is<ast::DiscardStatement>()); EXPECT_TRUE(e->continuing->statements[0]->Is<ast::DiscardStatement>());
} }

View File

@ -23,7 +23,7 @@ TEST_F(ParserImplTest, ParamList_Single) {
auto e = p->expect_param_list(); auto e = p->expect_param_list();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(e.errored); ASSERT_FALSE(e.errored);
EXPECT_EQ(e.value.size(), 1u); EXPECT_EQ(e.value.Length(), 1u);
EXPECT_EQ(e.value[0]->symbol, p->builder().Symbols().Get("a")); EXPECT_EQ(e.value[0]->symbol, p->builder().Symbols().Get("a"));
EXPECT_TRUE(e.value[0]->type->Is<ast::I32>()); EXPECT_TRUE(e.value[0]->type->Is<ast::I32>());
@ -41,7 +41,7 @@ TEST_F(ParserImplTest, ParamList_Multiple) {
auto e = p->expect_param_list(); auto e = p->expect_param_list();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(e.errored); ASSERT_FALSE(e.errored);
EXPECT_EQ(e.value.size(), 3u); EXPECT_EQ(e.value.Length(), 3u);
EXPECT_EQ(e.value[0]->symbol, p->builder().Symbols().Get("a")); EXPECT_EQ(e.value[0]->symbol, p->builder().Symbols().Get("a"));
EXPECT_TRUE(e.value[0]->type->Is<ast::I32>()); EXPECT_TRUE(e.value[0]->type->Is<ast::I32>());
@ -78,7 +78,7 @@ TEST_F(ParserImplTest, ParamList_Empty) {
auto e = p->expect_param_list(); auto e = p->expect_param_list();
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_FALSE(e.errored); ASSERT_FALSE(e.errored);
EXPECT_EQ(e.value.size(), 0u); EXPECT_EQ(e.value.Length(), 0u);
} }
TEST_F(ParserImplTest, ParamList_TrailingComma) { TEST_F(ParserImplTest, ParamList_TrailingComma) {
@ -86,7 +86,7 @@ TEST_F(ParserImplTest, ParamList_TrailingComma) {
auto e = p->expect_param_list(); auto e = p->expect_param_list();
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_FALSE(e.errored); ASSERT_FALSE(e.errored);
EXPECT_EQ(e.value.size(), 1u); EXPECT_EQ(e.value.Length(), 1u);
} }
TEST_F(ParserImplTest, ParamList_Attributes) { TEST_F(ParserImplTest, ParamList_Attributes) {
@ -95,7 +95,7 @@ TEST_F(ParserImplTest, ParamList_Attributes) {
auto e = p->expect_param_list(); auto e = p->expect_param_list();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(e.errored); ASSERT_FALSE(e.errored);
ASSERT_EQ(e.value.size(), 2u); ASSERT_EQ(e.value.Length(), 2u);
EXPECT_EQ(e.value[0]->symbol, p->builder().Symbols().Get("coord")); EXPECT_EQ(e.value[0]->symbol, p->builder().Symbols().Get("coord"));
ASSERT_TRUE(e.value[0]->type->Is<ast::Vector>()); ASSERT_TRUE(e.value[0]->type->Is<ast::Vector>());
@ -103,7 +103,7 @@ TEST_F(ParserImplTest, ParamList_Attributes) {
EXPECT_EQ(e.value[0]->type->As<ast::Vector>()->width, 4u); EXPECT_EQ(e.value[0]->type->As<ast::Vector>()->width, 4u);
EXPECT_TRUE(e.value[0]->Is<ast::Parameter>()); EXPECT_TRUE(e.value[0]->Is<ast::Parameter>());
auto attrs_0 = e.value[0]->attributes; auto attrs_0 = e.value[0]->attributes;
ASSERT_EQ(attrs_0.size(), 1u); ASSERT_EQ(attrs_0.Length(), 1u);
EXPECT_TRUE(attrs_0[0]->Is<ast::BuiltinAttribute>()); EXPECT_TRUE(attrs_0[0]->Is<ast::BuiltinAttribute>());
EXPECT_EQ(attrs_0[0]->As<ast::BuiltinAttribute>()->builtin, ast::BuiltinValue::kPosition); EXPECT_EQ(attrs_0[0]->As<ast::BuiltinAttribute>()->builtin, ast::BuiltinValue::kPosition);
@ -116,7 +116,7 @@ TEST_F(ParserImplTest, ParamList_Attributes) {
EXPECT_TRUE(e.value[1]->type->Is<ast::F32>()); EXPECT_TRUE(e.value[1]->type->Is<ast::F32>());
EXPECT_TRUE(e.value[1]->Is<ast::Parameter>()); EXPECT_TRUE(e.value[1]->Is<ast::Parameter>());
auto attrs_1 = e.value[1]->attributes; auto attrs_1 = e.value[1]->attributes;
ASSERT_EQ(attrs_1.size(), 1u); ASSERT_EQ(attrs_1.Length(), 1u);
EXPECT_TRUE(attrs_1[0]->Is<ast::LocationAttribute>()); EXPECT_TRUE(attrs_1[0]->Is<ast::LocationAttribute>());
EXPECT_EQ(attrs_1[0]->As<ast::LocationAttribute>()->value, 1u); EXPECT_EQ(attrs_1[0]->As<ast::LocationAttribute>()->value, 1u);

View File

@ -42,7 +42,7 @@ TEST_F(ParserImplTest, PrimaryExpression_TypeDecl) {
EXPECT_NE(call->target.type, nullptr); EXPECT_NE(call->target.type, nullptr);
ASSERT_EQ(call->args.size(), 4u); ASSERT_EQ(call->args.Length(), 4u);
const auto& val = call->args; const auto& val = call->args;
ASSERT_TRUE(val[0]->Is<ast::IntLiteralExpression>()); ASSERT_TRUE(val[0]->Is<ast::IntLiteralExpression>());
EXPECT_EQ(val[0]->As<ast::IntLiteralExpression>()->value, 1); EXPECT_EQ(val[0]->As<ast::IntLiteralExpression>()->value, 1);
@ -76,7 +76,7 @@ TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_ZeroConstructor) {
ASSERT_TRUE(e->Is<ast::CallExpression>()); ASSERT_TRUE(e->Is<ast::CallExpression>());
auto* call = e->As<ast::CallExpression>(); auto* call = e->As<ast::CallExpression>();
ASSERT_EQ(call->args.size(), 0u); ASSERT_EQ(call->args.Length(), 0u);
} }
TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_InvalidTypeDecl) { TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_InvalidTypeDecl) {
@ -140,7 +140,7 @@ TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_StructConstructor_Empty) {
ASSERT_NE(call->target.name, nullptr); ASSERT_NE(call->target.name, nullptr);
EXPECT_EQ(call->target.name->symbol, p->builder().Symbols().Get("S")); EXPECT_EQ(call->target.name->symbol, p->builder().Symbols().Get("S"));
ASSERT_EQ(call->args.size(), 0u); ASSERT_EQ(call->args.Length(), 0u);
} }
TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_StructConstructor_NotEmpty) { TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_StructConstructor_NotEmpty) {
@ -164,7 +164,7 @@ TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_StructConstructor_NotEmpty) {
ASSERT_NE(call->target.name, nullptr); ASSERT_NE(call->target.name, nullptr);
EXPECT_EQ(call->target.name->symbol, p->builder().Symbols().Get("S")); EXPECT_EQ(call->target.name->symbol, p->builder().Symbols().Get("S"));
ASSERT_EQ(call->args.size(), 2u); ASSERT_EQ(call->args.Length(), 2u);
ASSERT_TRUE(call->args[0]->Is<ast::IntLiteralExpression>()); ASSERT_TRUE(call->args[0]->Is<ast::IntLiteralExpression>());
EXPECT_EQ(call->args[0]->As<ast::IntLiteralExpression>()->value, 1u); EXPECT_EQ(call->args[0]->As<ast::IntLiteralExpression>()->value, 1u);
@ -239,7 +239,7 @@ TEST_F(ParserImplTest, PrimaryExpression_Cast) {
auto* call = e->As<ast::CallExpression>(); auto* call = e->As<ast::CallExpression>();
ASSERT_TRUE(call->target.type->Is<ast::F32>()); ASSERT_TRUE(call->target.type->Is<ast::F32>());
ASSERT_EQ(call->args.size(), 1u); ASSERT_EQ(call->args.Length(), 1u);
ASSERT_TRUE(call->args[0]->Is<ast::IntLiteralExpression>()); ASSERT_TRUE(call->args[0]->Is<ast::IntLiteralExpression>());
} }

View File

@ -99,7 +99,7 @@ TEST_F(ParserImplTest, SingularExpression_Call_Empty) {
EXPECT_EQ(c->target.name->symbol, p->builder().Symbols().Get("a")); EXPECT_EQ(c->target.name->symbol, p->builder().Symbols().Get("a"));
EXPECT_EQ(c->args.size(), 0u); EXPECT_EQ(c->args.Length(), 0u);
} }
TEST_F(ParserImplTest, SingularExpression_Call_WithArgs) { TEST_F(ParserImplTest, SingularExpression_Call_WithArgs) {
@ -115,7 +115,7 @@ TEST_F(ParserImplTest, SingularExpression_Call_WithArgs) {
EXPECT_EQ(c->target.name->symbol, p->builder().Symbols().Get("test")); EXPECT_EQ(c->target.name->symbol, p->builder().Symbols().Get("test"));
EXPECT_EQ(c->args.size(), 3u); EXPECT_EQ(c->args.Length(), 3u);
EXPECT_TRUE(c->args[0]->Is<ast::IntLiteralExpression>()); EXPECT_TRUE(c->args[0]->Is<ast::IntLiteralExpression>());
EXPECT_TRUE(c->args[1]->Is<ast::IdentifierExpression>()); EXPECT_TRUE(c->args[1]->Is<ast::IdentifierExpression>());
EXPECT_TRUE(c->args[2]->Is<ast::BinaryExpression>()); EXPECT_TRUE(c->args[2]->Is<ast::BinaryExpression>());
@ -130,7 +130,7 @@ TEST_F(ParserImplTest, SingularExpression_Call_TrailingComma) {
ASSERT_TRUE(e->Is<ast::CallExpression>()); ASSERT_TRUE(e->Is<ast::CallExpression>());
auto* c = e->As<ast::CallExpression>(); auto* c = e->As<ast::CallExpression>();
EXPECT_EQ(c->args.size(), 1u); EXPECT_EQ(c->args.Length(), 1u);
} }
TEST_F(ParserImplTest, SingularExpression_Call_InvalidArg) { TEST_F(ParserImplTest, SingularExpression_Call_InvalidArg) {

View File

@ -23,7 +23,7 @@ TEST_F(ParserImplTest, Statements) {
auto e = p->expect_statements(); auto e = p->expect_statements();
EXPECT_FALSE(e.errored); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e->size(), 2u); ASSERT_EQ(e->Length(), 2u);
EXPECT_TRUE(e.value[0]->Is<ast::DiscardStatement>()); EXPECT_TRUE(e.value[0]->Is<ast::DiscardStatement>());
EXPECT_TRUE(e.value[1]->Is<ast::ReturnStatement>()); EXPECT_TRUE(e.value[1]->Is<ast::ReturnStatement>());
} }
@ -33,7 +33,7 @@ TEST_F(ParserImplTest, Statements_Empty) {
auto e = p->expect_statements(); auto e = p->expect_statements();
EXPECT_FALSE(e.errored); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e->size(), 0u); ASSERT_EQ(e->Length(), 0u);
} }
} // namespace } // namespace

View File

@ -24,7 +24,7 @@ TEST_F(ParserImplTest, AttributeDecl_Parses) {
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
EXPECT_FALSE(attrs.errored); EXPECT_FALSE(attrs.errored);
EXPECT_TRUE(attrs.matched); EXPECT_TRUE(attrs.matched);
ASSERT_EQ(attrs.value.size(), 1u); ASSERT_EQ(attrs.value.Length(), 1u);
auto* invariant = attrs.value[0]->As<ast::Attribute>(); auto* invariant = attrs.value[0]->As<ast::Attribute>();
EXPECT_TRUE(invariant->Is<ast::InvariantAttribute>()); EXPECT_TRUE(invariant->Is<ast::InvariantAttribute>());
} }
@ -35,7 +35,7 @@ TEST_F(ParserImplTest, AttributeDecl_MissingParenLeft) {
EXPECT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
EXPECT_TRUE(attrs.errored); EXPECT_TRUE(attrs.errored);
EXPECT_FALSE(attrs.matched); EXPECT_FALSE(attrs.matched);
EXPECT_TRUE(attrs.value.empty()); EXPECT_TRUE(attrs.value.IsEmpty());
EXPECT_EQ(p->error(), "1:11: expected '(' for location attribute"); EXPECT_EQ(p->error(), "1:11: expected '(' for location attribute");
} }
@ -45,7 +45,7 @@ TEST_F(ParserImplTest, AttributeDecl_MissingValue) {
EXPECT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
EXPECT_TRUE(attrs.errored); EXPECT_TRUE(attrs.errored);
EXPECT_FALSE(attrs.matched); EXPECT_FALSE(attrs.matched);
EXPECT_TRUE(attrs.value.empty()); EXPECT_TRUE(attrs.value.IsEmpty());
EXPECT_EQ(p->error(), "1:11: expected signed integer literal for location attribute"); EXPECT_EQ(p->error(), "1:11: expected signed integer literal for location attribute");
} }
@ -55,7 +55,7 @@ TEST_F(ParserImplTest, AttributeDecl_MissingParenRight) {
EXPECT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
EXPECT_TRUE(attrs.errored); EXPECT_TRUE(attrs.errored);
EXPECT_FALSE(attrs.matched); EXPECT_FALSE(attrs.matched);
EXPECT_TRUE(attrs.value.empty()); EXPECT_TRUE(attrs.value.IsEmpty());
EXPECT_EQ(p->error(), "1:12: expected ')' for location attribute"); EXPECT_EQ(p->error(), "1:12: expected ')' for location attribute");
} }
@ -65,7 +65,7 @@ TEST_F(ParserImplTest, AttributeDecl_Invalidattribute) {
EXPECT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
EXPECT_TRUE(attrs.errored); EXPECT_TRUE(attrs.errored);
EXPECT_FALSE(attrs.matched); EXPECT_FALSE(attrs.matched);
EXPECT_TRUE(attrs.value.empty()); EXPECT_TRUE(attrs.value.IsEmpty());
} }
} // namespace } // namespace

View File

@ -25,12 +25,12 @@ TEST_F(ParserImplTest, StructBodyDecl_Parses) {
auto m = p->expect_struct_body_decl(); auto m = p->expect_struct_body_decl();
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_FALSE(m.errored); ASSERT_FALSE(m.errored);
ASSERT_EQ(m.value.size(), 1u); ASSERT_EQ(m.value.Length(), 1u);
const auto* mem = m.value[0]; const auto* mem = m.value[0];
EXPECT_EQ(mem->symbol, builder.Symbols().Get("a")); EXPECT_EQ(mem->symbol, builder.Symbols().Get("a"));
EXPECT_TRUE(mem->type->Is<ast::I32>()); EXPECT_TRUE(mem->type->Is<ast::I32>());
EXPECT_EQ(mem->attributes.size(), 0u); EXPECT_EQ(mem->attributes.Length(), 0u);
} }
TEST_F(ParserImplTest, StructBodyDecl_Parses_TrailingComma) { TEST_F(ParserImplTest, StructBodyDecl_Parses_TrailingComma) {
@ -41,12 +41,12 @@ TEST_F(ParserImplTest, StructBodyDecl_Parses_TrailingComma) {
auto m = p->expect_struct_body_decl(); auto m = p->expect_struct_body_decl();
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_FALSE(m.errored); ASSERT_FALSE(m.errored);
ASSERT_EQ(m.value.size(), 1u); ASSERT_EQ(m.value.Length(), 1u);
const auto* mem = m.value[0]; const auto* mem = m.value[0];
EXPECT_EQ(mem->symbol, builder.Symbols().Get("a")); EXPECT_EQ(mem->symbol, builder.Symbols().Get("a"));
EXPECT_TRUE(mem->type->Is<ast::I32>()); EXPECT_TRUE(mem->type->Is<ast::I32>());
EXPECT_EQ(mem->attributes.size(), 0u); EXPECT_EQ(mem->attributes.Length(), 0u);
} }
TEST_F(ParserImplTest, StructBodyDecl_ParsesEmpty) { TEST_F(ParserImplTest, StructBodyDecl_ParsesEmpty) {
@ -54,7 +54,7 @@ TEST_F(ParserImplTest, StructBodyDecl_ParsesEmpty) {
auto m = p->expect_struct_body_decl(); auto m = p->expect_struct_body_decl();
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_FALSE(m.errored); ASSERT_FALSE(m.errored);
ASSERT_EQ(m.value.size(), 0u); ASSERT_EQ(m.value.Length(), 0u);
} }
TEST_F(ParserImplTest, StructBodyDecl_InvalidAlign) { TEST_F(ParserImplTest, StructBodyDecl_InvalidAlign) {

View File

@ -30,7 +30,7 @@ struct S {
EXPECT_TRUE(s.matched); EXPECT_TRUE(s.matched);
ASSERT_NE(s.value, nullptr); ASSERT_NE(s.value, nullptr);
ASSERT_EQ(s->name, p->builder().Symbols().Register("S")); ASSERT_EQ(s->name, p->builder().Symbols().Register("S"));
ASSERT_EQ(s->members.size(), 2u); ASSERT_EQ(s->members.Length(), 2u);
EXPECT_EQ(s->members[0]->symbol, p->builder().Symbols().Register("a")); EXPECT_EQ(s->members[0]->symbol, p->builder().Symbols().Register("a"));
EXPECT_EQ(s->members[1]->symbol, p->builder().Symbols().Register("b")); EXPECT_EQ(s->members[1]->symbol, p->builder().Symbols().Register("b"));
} }
@ -64,7 +64,7 @@ struct $struct {
EXPECT_TRUE(s.matched); EXPECT_TRUE(s.matched);
ASSERT_NE(s.value, nullptr); ASSERT_NE(s.value, nullptr);
ASSERT_EQ(s->name, p->builder().Symbols().Register(struct_ident)); ASSERT_EQ(s->name, p->builder().Symbols().Register(struct_ident));
ASSERT_EQ(s->members.size(), 2u); ASSERT_EQ(s->members.Length(), 2u);
EXPECT_EQ(s->members[0]->symbol, p->builder().Symbols().Register(member_a_ident)); EXPECT_EQ(s->members[0]->symbol, p->builder().Symbols().Register(member_a_ident));
EXPECT_EQ(s->members[1]->symbol, p->builder().Symbols().Register(member_b_ident)); EXPECT_EQ(s->members[1]->symbol, p->builder().Symbols().Register(member_b_ident));
} }
@ -77,7 +77,7 @@ TEST_F(ParserImplTest, StructDecl_EmptyMembers) {
EXPECT_FALSE(s.errored); EXPECT_FALSE(s.errored);
EXPECT_TRUE(s.matched); EXPECT_TRUE(s.matched);
ASSERT_NE(s.value, nullptr); ASSERT_NE(s.value, nullptr);
ASSERT_EQ(s->members.size(), 0u); ASSERT_EQ(s->members.Length(), 0u);
} }
TEST_F(ParserImplTest, StructDecl_MissingIdent) { TEST_F(ParserImplTest, StructDecl_MissingIdent) {

View File

@ -23,7 +23,7 @@ TEST_F(ParserImplTest, AttributeDecl_EmptyStr) {
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
EXPECT_FALSE(attrs.errored); EXPECT_FALSE(attrs.errored);
EXPECT_FALSE(attrs.matched); EXPECT_FALSE(attrs.matched);
EXPECT_EQ(attrs.value.size(), 0u); EXPECT_EQ(attrs.value.Length(), 0u);
} }
TEST_F(ParserImplTest, AttributeDecl_Single) { TEST_F(ParserImplTest, AttributeDecl_Single) {
@ -32,7 +32,7 @@ TEST_F(ParserImplTest, AttributeDecl_Single) {
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
EXPECT_FALSE(attrs.errored); EXPECT_FALSE(attrs.errored);
EXPECT_TRUE(attrs.matched); EXPECT_TRUE(attrs.matched);
ASSERT_EQ(attrs.value.size(), 1u); ASSERT_EQ(attrs.value.Length(), 1u);
auto* attr = attrs.value[0]->As<ast::Attribute>(); auto* attr = attrs.value[0]->As<ast::Attribute>();
ASSERT_NE(attr, nullptr); ASSERT_NE(attr, nullptr);
EXPECT_TRUE(attr->Is<ast::StructMemberSizeAttribute>()); EXPECT_TRUE(attr->Is<ast::StructMemberSizeAttribute>());

Some files were not shown because too many files have changed in this diff Show More