diff --git a/src/writer/wgsl/generator_impl.cc b/src/writer/wgsl/generator_impl.cc index 09c20a32d0..46c6e65a4d 100644 --- a/src/writer/wgsl/generator_impl.cc +++ b/src/writer/wgsl/generator_impl.cc @@ -16,10 +16,16 @@ #include +#include "src/ast/array_accessor_expression.h" #include "src/ast/binding_decoration.h" +#include "src/ast/bool_literal.h" #include "src/ast/builtin_decoration.h" +#include "src/ast/const_initializer_expression.h" #include "src/ast/decorated_variable.h" +#include "src/ast/float_literal.h" #include "src/ast/identifier_expression.h" +#include "src/ast/initializer_expression.h" +#include "src/ast/int_literal.h" #include "src/ast/location_decoration.h" #include "src/ast/set_decoration.h" #include "src/ast/struct.h" @@ -30,6 +36,8 @@ #include "src/ast/type/pointer_type.h" #include "src/ast/type/struct_type.h" #include "src/ast/type/vector_type.h" +#include "src/ast/type_initializer_expression.h" +#include "src/ast/uint_literal.h" namespace tint { namespace writer { @@ -106,19 +114,100 @@ bool GeneratorImpl::EmitEntryPoint(const ast::EntryPoint* ep) { } bool GeneratorImpl::EmitExpression(ast::Expression* expr) { + if (expr->IsArrayAccessor()) { + return EmitArrayAccessor(expr->AsArrayAccessor()); + } if (expr->IsIdentifier()) { - bool first = true; - for (const auto& part : expr->AsIdentifier()->name()) { - if (!first) { - out_ << "::"; - } - first = false; - out_ << part; - } - } else { - error_ = "unknown expression type"; + return EmitIdentifier(expr->AsIdentifier()); + } + if (expr->IsInitializer()) { + return EmitInitializer(expr->AsInitializer()); + } + + error_ = "unknown expression type"; + return false; +} + +bool GeneratorImpl::EmitArrayAccessor(ast::ArrayAccessorExpression* expr) { + if (!EmitExpression(expr->array())) { return false; } + out_ << "["; + + if (!EmitExpression(expr->idx_expr())) { + return false; + } + out_ << "]"; + + return true; +} + +bool GeneratorImpl::EmitInitializer(ast::InitializerExpression* expr) { + if (expr->IsConstInitializer()) { + return EmitConstInitializer(expr->AsConstInitializer()); + } + return EmitTypeInitializer(expr->AsTypeInitializer()); +} + +bool GeneratorImpl::EmitTypeInitializer(ast::TypeInitializerExpression* expr) { + if (!EmitType(expr->type())) { + return false; + } + + out_ << "("; + + bool first = true; + for (const auto& e : expr->values()) { + if (!first) { + out_ << ", "; + } + first = false; + + if (!EmitExpression(e.get())) { + return false; + } + } + + out_ << ")"; + return true; +} + +bool GeneratorImpl::EmitConstInitializer( + ast::ConstInitializerExpression* expr) { + auto lit = expr->literal(); + if (lit->IsBool()) { + out_ << (lit->AsBool()->IsTrue() ? "true" : "false"); + } else if (lit->IsFloat()) { + auto flags = out_.flags(); + auto precision = out_.precision(); + + out_.flags(flags | std::ios_base::showpoint); + out_.precision(std::numeric_limits::max_digits10); + + out_ << lit->AsFloat()->value(); + + out_.precision(precision); + out_.flags(flags); + } else if (lit->IsInt()) { + out_ << lit->AsInt()->value(); + } else if (lit->IsUint()) { + out_ << lit->AsUint()->value() << "u"; + } else { + error_ = "unknown literal type"; + return false; + } + return true; +} + +bool GeneratorImpl::EmitIdentifier(ast::IdentifierExpression* expr) { + bool first = true; + for (const auto& part : expr->AsIdentifier()->name()) { + if (!first) { + out_ << "::"; + } + first = false; + out_ << part; + } return true; } diff --git a/src/writer/wgsl/generator_impl.h b/src/writer/wgsl/generator_impl.h index 9d526a89ae..3ecc17c0c7 100644 --- a/src/writer/wgsl/generator_impl.h +++ b/src/writer/wgsl/generator_impl.h @@ -18,11 +18,16 @@ #include #include +#include "src/ast/array_accessor_expression.h" +#include "src/ast/const_initializer_expression.h" #include "src/ast/entry_point.h" +#include "src/ast/identifier_expression.h" #include "src/ast/import.h" +#include "src/ast/initializer_expression.h" #include "src/ast/module.h" #include "src/ast/type/alias_type.h" #include "src/ast/type/type.h" +#include "src/ast/type_initializer_expression.h" #include "src/ast/variable.h" namespace tint { @@ -65,6 +70,14 @@ class GeneratorImpl { /// @param alias the alias to generate /// @returns true if the alias was emitted bool EmitAliasType(const ast::type::AliasType* alias); + /// Handles an array accessor expression + /// @param expr the expression to emit + /// @returns true if the array accessor was emitted + bool EmitArrayAccessor(ast::ArrayAccessorExpression* expr); + /// Handles generating a const initializer + /// @param expr the const initializer expression + /// @returns true if the initializer is emitted + bool EmitConstInitializer(ast::ConstInitializerExpression* expr); /// Handles generating an entry_point command /// @param ep the entry point /// @returns true if the entry point was emitted @@ -73,14 +86,26 @@ class GeneratorImpl { /// @param expr the expression /// @returns true if the expression was emitted bool EmitExpression(ast::Expression* expr); + /// Handles generating an identifier expression + /// @param expr the identifier expression + /// @returns true if the identifeir was emitted + bool EmitIdentifier(ast::IdentifierExpression* expr); /// Handles generating an import command /// @param import the import to generate /// @returns true if the import was emitted bool EmitImport(const ast::Import* import); + /// Handles generating initializer expressions + /// @param expr the initializer expression + /// @returns true if the expression was emitted + bool EmitInitializer(ast::InitializerExpression* expr); /// Handles generating type /// @param type the type to generate /// @returns true if the type is emitted bool EmitType(ast::type::Type* type); + /// Handles emitting a type initializer + /// @param expr the type initializer expression + /// @returns true if the initializer is emitted + bool EmitTypeInitializer(ast::TypeInitializerExpression* expr); /// Handles generating a variable /// @param var the variable to generate /// @returns true if the variable was emitted diff --git a/src/writer/wgsl/generator_impl_test.cc b/src/writer/wgsl/generator_impl_test.cc index 813d71bb4f..cb05e5882a 100644 --- a/src/writer/wgsl/generator_impl_test.cc +++ b/src/writer/wgsl/generator_impl_test.cc @@ -19,11 +19,15 @@ #include #include "gtest/gtest.h" +#include "src/ast/array_accessor_expression.h" #include "src/ast/binding_decoration.h" +#include "src/ast/bool_literal.h" #include "src/ast/builtin.h" #include "src/ast/builtin_decoration.h" #include "src/ast/decorated_variable.h" +#include "src/ast/float_literal.h" #include "src/ast/identifier_expression.h" +#include "src/ast/int_literal.h" #include "src/ast/location_decoration.h" #include "src/ast/set_decoration.h" #include "src/ast/struct.h" @@ -41,6 +45,7 @@ #include "src/ast/type/u32_type.h" #include "src/ast/type/vector_type.h" #include "src/ast/type/void_type.h" +#include "src/ast/uint_literal.h" #include "src/ast/variable.h" namespace tint { @@ -57,12 +62,12 @@ TEST_F(GeneratorImplTest, EmitAliasType_F32) { ast::type::AliasType alias("a", &f32); GeneratorImpl g; - ASSERT_TRUE(g.EmitAliasType(&alias)); + ASSERT_TRUE(g.EmitAliasType(&alias)) << g.error(); EXPECT_EQ(g.result(), R"(type a = f32; )"); } -TEST_F(GeneratorImplTest, DISABLED_EmitAliasType_Struct) { +TEST_F(GeneratorImplTest, EmitAliasType_Struct) { ast::type::I32Type i32; ast::type::F32Type f32; @@ -82,11 +87,11 @@ TEST_F(GeneratorImplTest, DISABLED_EmitAliasType_Struct) { ast::type::AliasType alias("a", &s); GeneratorImpl g; - ASSERT_TRUE(g.EmitAliasType(&alias)); + ASSERT_TRUE(g.EmitAliasType(&alias)) << g.error(); EXPECT_EQ(g.result(), R"(type a = struct { a : f32; [[offset 4]] b : i32; -} +}; )"); } @@ -94,7 +99,7 @@ TEST_F(GeneratorImplTest, EmitEntryPoint_NoName) { ast::EntryPoint ep(ast::PipelineStage::kFragment, "", "frag_main"); GeneratorImpl g; - ASSERT_TRUE(g.EmitEntryPoint(&ep)); + ASSERT_TRUE(g.EmitEntryPoint(&ep)) << g.error(); EXPECT_EQ(g.result(), R"(entry_point fragment = frag_main; )"); } @@ -103,7 +108,7 @@ TEST_F(GeneratorImplTest, EmitEntryPoint_WithName) { ast::EntryPoint ep(ast::PipelineStage::kFragment, "main", "frag_main"); GeneratorImpl g; - ASSERT_TRUE(g.EmitEntryPoint(&ep)); + ASSERT_TRUE(g.EmitEntryPoint(&ep)) << g.error(); EXPECT_EQ(g.result(), R"(entry_point fragment as "main" = frag_main; )"); } @@ -112,7 +117,7 @@ TEST_F(GeneratorImplTest, EmitImport) { ast::Import import("GLSL.std.450", "std::glsl"); GeneratorImpl g; - ASSERT_TRUE(g.EmitImport(&import)); + ASSERT_TRUE(g.EmitImport(&import)) << g.error(); EXPECT_EQ(g.result(), R"(import "GLSL.std.450" as std::glsl; )"); } @@ -122,7 +127,7 @@ TEST_F(GeneratorImplTest, EmitType_Alias) { ast::type::AliasType alias("alias", &f32); GeneratorImpl g; - ASSERT_TRUE(g.EmitType(&alias)); + ASSERT_TRUE(g.EmitType(&alias)) << g.error(); EXPECT_EQ(g.result(), "alias"); } @@ -131,7 +136,7 @@ TEST_F(GeneratorImplTest, EmitType_Array) { ast::type::ArrayType a(&b, 4); GeneratorImpl g; - ASSERT_TRUE(g.EmitType(&a)); + ASSERT_TRUE(g.EmitType(&a)) << g.error(); EXPECT_EQ(g.result(), "array"); } @@ -140,7 +145,7 @@ TEST_F(GeneratorImplTest, EmitType_RuntimeArray) { ast::type::ArrayType a(&b); GeneratorImpl g; - ASSERT_TRUE(g.EmitType(&a)); + ASSERT_TRUE(g.EmitType(&a)) << g.error(); EXPECT_EQ(g.result(), "array"); } @@ -148,7 +153,7 @@ TEST_F(GeneratorImplTest, EmitType_Bool) { ast::type::BoolType b; GeneratorImpl g; - ASSERT_TRUE(g.EmitType(&b)); + ASSERT_TRUE(g.EmitType(&b)) << g.error(); EXPECT_EQ(g.result(), "bool"); } @@ -156,7 +161,7 @@ TEST_F(GeneratorImplTest, EmitType_F32) { ast::type::F32Type f32; GeneratorImpl g; - ASSERT_TRUE(g.EmitType(&f32)); + ASSERT_TRUE(g.EmitType(&f32)) << g.error(); EXPECT_EQ(g.result(), "f32"); } @@ -164,7 +169,7 @@ TEST_F(GeneratorImplTest, EmitType_I32) { ast::type::I32Type i32; GeneratorImpl g; - ASSERT_TRUE(g.EmitType(&i32)); + ASSERT_TRUE(g.EmitType(&i32)) << g.error(); EXPECT_EQ(g.result(), "i32"); } @@ -173,7 +178,7 @@ TEST_F(GeneratorImplTest, EmitType_Matrix) { ast::type::MatrixType m(&f32, 3, 2); GeneratorImpl g; - ASSERT_TRUE(g.EmitType(&m)); + ASSERT_TRUE(g.EmitType(&m)) << g.error(); EXPECT_EQ(g.result(), "mat2x3"); } @@ -182,7 +187,7 @@ TEST_F(GeneratorImplTest, EmitType_Pointer) { ast::type::PointerType p(&f32, ast::StorageClass::kWorkgroup); GeneratorImpl g; - ASSERT_TRUE(g.EmitType(&p)); + ASSERT_TRUE(g.EmitType(&p)) << g.error(); EXPECT_EQ(g.result(), "ptr"); } @@ -205,7 +210,7 @@ TEST_F(GeneratorImplTest, EmitType_Struct) { ast::type::StructType s(std::move(str)); GeneratorImpl g; - ASSERT_TRUE(g.EmitType(&s)); + ASSERT_TRUE(g.EmitType(&s)) << g.error(); EXPECT_EQ(g.result(), R"(struct { a : i32; [[offset 4]] b : f32; @@ -232,7 +237,7 @@ TEST_F(GeneratorImplTest, EmitType_Struct_WithDecoration) { ast::type::StructType s(std::move(str)); GeneratorImpl g; - ASSERT_TRUE(g.EmitType(&s)); + ASSERT_TRUE(g.EmitType(&s)) << g.error(); EXPECT_EQ(g.result(), R"([[block]] struct { a : i32; [[offset 4]] b : f32; @@ -243,7 +248,7 @@ TEST_F(GeneratorImplTest, EmitType_U32) { ast::type::U32Type u32; GeneratorImpl g; - ASSERT_TRUE(g.EmitType(&u32)); + ASSERT_TRUE(g.EmitType(&u32)) << g.error(); EXPECT_EQ(g.result(), "u32"); } @@ -252,7 +257,7 @@ TEST_F(GeneratorImplTest, EmitType_Vector) { ast::type::VectorType v(&f32, 3); GeneratorImpl g; - ASSERT_TRUE(g.EmitType(&v)); + ASSERT_TRUE(g.EmitType(&v)) << g.error(); EXPECT_EQ(g.result(), "vec3"); } @@ -260,7 +265,7 @@ TEST_F(GeneratorImplTest, EmitType_Void) { ast::type::VoidType v; GeneratorImpl g; - ASSERT_TRUE(g.EmitType(&v)); + ASSERT_TRUE(g.EmitType(&v)) << g.error(); EXPECT_EQ(g.result(), "void"); } @@ -269,7 +274,7 @@ TEST_F(GeneratorImplTest, EmitVariable) { ast::Variable v("a", ast::StorageClass::kNone, &f32); GeneratorImpl g; - ASSERT_TRUE(g.EmitVariable(&v)); + ASSERT_TRUE(g.EmitVariable(&v)) << g.error(); EXPECT_EQ(g.result(), R"(var a : f32; )"); } @@ -279,7 +284,7 @@ TEST_F(GeneratorImplTest, EmitVariable_StorageClass) { ast::Variable v("a", ast::StorageClass::kInput, &f32); GeneratorImpl g; - ASSERT_TRUE(g.EmitVariable(&v)); + ASSERT_TRUE(g.EmitVariable(&v)) << g.error(); EXPECT_EQ(g.result(), R"(var a : f32; )"); } @@ -296,7 +301,7 @@ TEST_F(GeneratorImplTest, EmitVariable_Decorated) { dv.set_decorations(std::move(decos)); GeneratorImpl g; - ASSERT_TRUE(g.EmitVariable(&dv)); + ASSERT_TRUE(g.EmitVariable(&dv)) << g.error(); EXPECT_EQ(g.result(), R"([[location 2]] var a : f32; )"); } @@ -317,7 +322,7 @@ TEST_F(GeneratorImplTest, EmitVariable_Decorated_Multiple) { dv.set_decorations(std::move(decos)); GeneratorImpl g; - ASSERT_TRUE(g.EmitVariable(&dv)); + ASSERT_TRUE(g.EmitVariable(&dv)) << g.error(); EXPECT_EQ(g.result(), R"([[builtin position, binding 0, set 1, location 2]] var a : f32; )"); @@ -331,7 +336,7 @@ TEST_F(GeneratorImplTest, EmitVariable_Initializer) { v.set_initializer(std::move(ident)); GeneratorImpl g; - ASSERT_TRUE(g.EmitVariable(&v)); + ASSERT_TRUE(g.EmitVariable(&v)) << g.error(); EXPECT_EQ(g.result(), R"(var a : f32 = initializer; )"); } @@ -345,27 +350,242 @@ TEST_F(GeneratorImplTest, EmitVariable_Const) { v.set_is_const(true); GeneratorImpl g; - ASSERT_TRUE(g.EmitVariable(&v)); + ASSERT_TRUE(g.EmitVariable(&v)) << g.error(); EXPECT_EQ(g.result(), R"(const a : f32 = initializer; )"); } -TEST_F(GeneratorImplTest, EmitExpression_Identifier) { - ast::IdentifierExpression i("init"); +TEST_F(GeneratorImplTest, EmitExpression_ArrayAccessor) { + auto lit = std::make_unique(5); + auto idx = std::make_unique(std::move(lit)); + auto ary = std::make_unique("ary"); + + ast::ArrayAccessorExpression expr(std::move(ary), std::move(idx)); GeneratorImpl g; - ASSERT_TRUE(g.EmitExpression(&i)); - EXPECT_EQ(g.result(), "init"); + ASSERT_TRUE(g.EmitExpression(&expr)) << g.error(); + EXPECT_EQ(g.result(), "ary[5]"); } -TEST_F(GeneratorImplTest, EmitExpression_Identifier_MultipleNames) { +TEST_F(GeneratorImplTest, EmitExpression_Identifier) { + ast::IdentifierExpression i(std::vector{"std", "glsl"}); + + GeneratorImpl g; + ASSERT_TRUE(g.EmitExpression(&i)) << g.error(); + EXPECT_EQ(g.result(), "std::glsl"); +} + +TEST_F(GeneratorImplTest, EmitArrayAccessor) { + auto ary = std::make_unique("ary"); + auto idx = std::make_unique("idx"); + + ast::ArrayAccessorExpression expr(std::move(ary), std::move(idx)); + + GeneratorImpl g; + ASSERT_TRUE(g.EmitArrayAccessor(&expr)) << g.error(); + EXPECT_EQ(g.result(), "ary[idx]"); +} + +TEST_F(GeneratorImplTest, EmitIdentifierExpression_Single) { + ast::IdentifierExpression i("glsl"); + + GeneratorImpl g; + ASSERT_TRUE(g.EmitExpression(&i)) << g.error(); + EXPECT_EQ(g.result(), "glsl"); +} + +TEST_F(GeneratorImplTest, EmitIdentifierExpression_MultipleNames) { ast::IdentifierExpression i({"std", "glsl", "init"}); GeneratorImpl g; - ASSERT_TRUE(g.EmitExpression(&i)); + ASSERT_TRUE(g.EmitExpression(&i)) << g.error(); EXPECT_EQ(g.result(), "std::glsl::init"); } +TEST_F(GeneratorImplTest, EmitInitializer_Bool) { + auto lit = std::make_unique(false); + ast::ConstInitializerExpression expr(std::move(lit)); + + GeneratorImpl g; + ASSERT_TRUE(g.EmitInitializer(&expr)) << g.error(); + EXPECT_EQ(g.result(), "false"); +} + +TEST_F(GeneratorImplTest, EmitInitializer_Int) { + auto lit = std::make_unique(-12345); + ast::ConstInitializerExpression expr(std::move(lit)); + + GeneratorImpl g; + ASSERT_TRUE(g.EmitInitializer(&expr)) << g.error(); + EXPECT_EQ(g.result(), "-12345"); +} + +TEST_F(GeneratorImplTest, EmitInitializer_UInt) { + auto lit = std::make_unique(56779); + ast::ConstInitializerExpression expr(std::move(lit)); + + GeneratorImpl g; + ASSERT_TRUE(g.EmitInitializer(&expr)) << g.error(); + EXPECT_EQ(g.result(), "56779u"); +} + +TEST_F(GeneratorImplTest, EmitInitializer_Float) { + auto lit = std::make_unique(1.5e27); + ast::ConstInitializerExpression expr(std::move(lit)); + + GeneratorImpl g; + ASSERT_TRUE(g.EmitInitializer(&expr)) << g.error(); + EXPECT_EQ(g.result(), "1.49999995e+27"); +} + +TEST_F(GeneratorImplTest, EmitInitializer_Type_Float) { + ast::type::F32Type f32; + + auto lit = std::make_unique(-1.2e-5); + std::vector> values; + values.push_back( + std::make_unique(std::move(lit))); + + ast::TypeInitializerExpression expr(&f32, std::move(values)); + + GeneratorImpl g; + ASSERT_TRUE(g.EmitInitializer(&expr)) << g.error(); + EXPECT_EQ(g.result(), "f32(-1.20000004e-05)"); +} + +TEST_F(GeneratorImplTest, EmitInitializer_Type_Bool) { + ast::type::BoolType b; + + auto lit = std::make_unique(true); + std::vector> values; + values.push_back( + std::make_unique(std::move(lit))); + + ast::TypeInitializerExpression expr(&b, std::move(values)); + + GeneratorImpl g; + ASSERT_TRUE(g.EmitInitializer(&expr)) << g.error(); + EXPECT_EQ(g.result(), "bool(true)"); +} + +TEST_F(GeneratorImplTest, EmitInitializer_Type_Int) { + ast::type::I32Type i32; + + auto lit = std::make_unique(-12345); + std::vector> values; + values.push_back( + std::make_unique(std::move(lit))); + + ast::TypeInitializerExpression expr(&i32, std::move(values)); + + GeneratorImpl g; + ASSERT_TRUE(g.EmitInitializer(&expr)) << g.error(); + EXPECT_EQ(g.result(), "i32(-12345)"); +} + +TEST_F(GeneratorImplTest, EmitInitializer_Type_Uint) { + ast::type::U32Type u32; + + auto lit = std::make_unique(12345); + std::vector> values; + values.push_back( + std::make_unique(std::move(lit))); + + ast::TypeInitializerExpression expr(&u32, std::move(values)); + + GeneratorImpl g; + ASSERT_TRUE(g.EmitInitializer(&expr)) << g.error(); + EXPECT_EQ(g.result(), "u32(12345u)"); +} + +TEST_F(GeneratorImplTest, EmitInitializer_Type_Vec) { + ast::type::F32Type f32; + ast::type::VectorType vec(&f32, 3); + + auto lit1 = std::make_unique(1.f); + auto lit2 = std::make_unique(2.f); + auto lit3 = std::make_unique(3.f); + std::vector> values; + values.push_back( + std::make_unique(std::move(lit1))); + values.push_back( + std::make_unique(std::move(lit2))); + values.push_back( + std::make_unique(std::move(lit3))); + + ast::TypeInitializerExpression expr(&vec, std::move(values)); + + GeneratorImpl g; + ASSERT_TRUE(g.EmitInitializer(&expr)) << g.error(); + EXPECT_EQ(g.result(), "vec3(1.00000000, 2.00000000, 3.00000000)"); +} + +TEST_F(GeneratorImplTest, EmitInitializer_Type_Mat) { + ast::type::F32Type f32; + ast::type::MatrixType mat(&f32, 3, 2); + + ast::type::VectorType vec(&f32, 2); + + std::vector> mat_values; + + for (size_t i = 0; i < 3; i++) { + auto lit1 = std::make_unique(1.f + (i * 2)); + auto lit2 = std::make_unique(2.f + (i * 2)); + + std::vector> values; + values.push_back( + std::make_unique(std::move(lit1))); + values.push_back( + std::make_unique(std::move(lit2))); + + mat_values.push_back(std::make_unique( + &vec, std::move(values))); + } + + ast::TypeInitializerExpression expr(&mat, std::move(mat_values)); + + GeneratorImpl g; + ASSERT_TRUE(g.EmitInitializer(&expr)) << g.error(); + EXPECT_EQ(g.result(), + std::string("mat2x3(vec2(1.00000000, 2.00000000), ") + + "vec2(3.00000000, 4.00000000), " + + "vec2(5.00000000, 6.00000000))"); +} + +TEST_F(GeneratorImplTest, EmitInitializer_Type_Array) { + ast::type::F32Type f32; + ast::type::VectorType vec(&f32, 3); + ast::type::ArrayType ary(&vec, 3); + + std::vector> ary_values; + + for (size_t i = 0; i < 3; i++) { + auto lit1 = std::make_unique(1.f + (i * 3)); + auto lit2 = std::make_unique(2.f + (i * 3)); + auto lit3 = std::make_unique(3.f + (i * 3)); + + std::vector> values; + values.push_back( + std::make_unique(std::move(lit1))); + values.push_back( + std::make_unique(std::move(lit2))); + values.push_back( + std::make_unique(std::move(lit3))); + + ary_values.push_back(std::make_unique( + &vec, std::move(values))); + } + + ast::TypeInitializerExpression expr(&ary, std::move(ary_values)); + + GeneratorImpl g; + ASSERT_TRUE(g.EmitInitializer(&expr)) << g.error(); + EXPECT_EQ(g.result(), std::string("array, 3>(") + + "vec3(1.00000000, 2.00000000, 3.00000000), " + + "vec3(4.00000000, 5.00000000, 6.00000000), " + + "vec3(7.00000000, 8.00000000, 9.00000000))"); +} + } // namespace } // namespace wgsl } // namespace writer