Use a context object instead of a singleton

This Cl replaces the TypeManager singleton with a context object.

Bug: tint:29
Change-Id: Ia662709db1b562c34955633977ce4363f28f238e
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/17780
Reviewed-by: David Neto <dneto@google.com>
This commit is contained in:
dan sinclair 2020-03-25 19:16:36 +00:00 committed by dan sinclair
parent 0984214d8b
commit 9981b63fa4
88 changed files with 2756 additions and 2378 deletions

View File

@ -17,8 +17,10 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include "src/context.h"
#include "src/reader/reader.h" #include "src/reader/reader.h"
#include "src/type_determiner.h" #include "src/type_determiner.h"
#include "src/type_manager.h"
#include "src/validator.h" #include "src/validator.h"
#include "src/writer/writer.h" #include "src/writer/writer.h"
@ -250,6 +252,11 @@ int main(int argc, const char** argv) {
return 1; return 1;
} }
tint::TypeManager type_manager;
tint::Context ctx;
ctx.type_mgr = &type_manager;
std::unique_ptr<tint::reader::Reader> reader; std::unique_ptr<tint::reader::Reader> reader;
#if TINT_BUILD_WGSL_READER #if TINT_BUILD_WGSL_READER
if (options.input_filename.size() > 5 && if (options.input_filename.size() > 5 &&
@ -260,7 +267,7 @@ int main(int argc, const char** argv) {
return 1; return 1;
} }
reader = std::make_unique<tint::reader::wgsl::Parser>( reader = std::make_unique<tint::reader::wgsl::Parser>(
std::string(data.begin(), data.end())); ctx, std::string(data.begin(), data.end()));
} }
#endif // TINT_BUILD_WGSL_READER #endif // TINT_BUILD_WGSL_READER
@ -272,7 +279,7 @@ int main(int argc, const char** argv) {
if (!ReadFile<uint32_t>(options.input_filename, &data)) { if (!ReadFile<uint32_t>(options.input_filename, &data)) {
return 1; return 1;
} }
reader = std::make_unique<tint::reader::spirv::Parser>(data); reader = std::make_unique<tint::reader::spirv::Parser>(ctx, data);
} }
#endif // TINT_BUILD_SPV_READER #endif // TINT_BUILD_SPV_READER

View File

@ -387,6 +387,7 @@ if(${TINT_BUILD_WGSL_READER})
reader/wgsl/parser_impl_switch_body_test.cc reader/wgsl/parser_impl_switch_body_test.cc
reader/wgsl/parser_impl_switch_stmt_test.cc reader/wgsl/parser_impl_switch_stmt_test.cc
reader/wgsl/parser_impl_test.cc reader/wgsl/parser_impl_test.cc
reader/wgsl/parser_impl_test_helper.h
reader/wgsl/parser_impl_type_alias_test.cc reader/wgsl/parser_impl_type_alias_test.cc
reader/wgsl/parser_impl_type_decl_test.cc reader/wgsl/parser_impl_type_decl_test.cc
reader/wgsl/parser_impl_unary_expression_test.cc reader/wgsl/parser_impl_unary_expression_test.cc

28
src/context.h Normal file
View File

@ -0,0 +1,28 @@
// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_CONTEXT_H_
#define SRC_CONTEXT_H_
#include "src/type_manager.h"
namespace tint {
struct Context {
TypeManager* type_mgr = nullptr;
};
} // namespace tint
#endif // SRC_CONTEXT_H_

View File

@ -17,7 +17,7 @@
namespace tint { namespace tint {
namespace reader { namespace reader {
Reader::Reader() = default; Reader::Reader(const Context& ctx) : ctx_(ctx) {}
Reader::~Reader() = default; Reader::~Reader() = default;

View File

@ -18,6 +18,7 @@
#include <string> #include <string>
#include "src/ast/module.h" #include "src/ast/module.h"
#include "src/context.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
@ -41,12 +42,16 @@ class Reader {
protected: protected:
/// Constructor /// Constructor
Reader(); /// @param ctx the context object
explicit Reader(const Context& ctx);
/// Sets the error string /// Sets the error string
/// @param msg the error message /// @param msg the error message
void set_error(const std::string& msg) { error_ = msg; } void set_error(const std::string& msg) { error_ = msg; }
/// The Tint context object
const Context& ctx_;
/// An error message, if an error was encountered /// An error message, if an error was encountered
std::string error_; std::string error_;
}; };

View File

@ -20,8 +20,8 @@ namespace tint {
namespace reader { namespace reader {
namespace spirv { namespace spirv {
Parser::Parser(const std::vector<uint32_t>& spv_binary) Parser::Parser(const Context& ctx, const std::vector<uint32_t>& spv_binary)
: Reader(), impl_(std::make_unique<ParserImpl>(spv_binary)) {} : Reader(ctx), impl_(std::make_unique<ParserImpl>(ctx, spv_binary)) {}
Parser::~Parser() = default; Parser::~Parser() = default;

View File

@ -31,8 +31,9 @@ class ParserImpl;
class Parser : public Reader { class Parser : public Reader {
public: public:
/// Creates a new parser /// Creates a new parser
/// @param ctx the context object
/// @param input the input data to parse /// @param input the input data to parse
explicit Parser(const std::vector<uint32_t>& input); Parser(const Context& ctx, const std::vector<uint32_t>& input);
/// Destructor /// Destructor
~Parser() override; ~Parser() override;

View File

@ -44,8 +44,9 @@ const spv_target_env kTargetEnv = SPV_ENV_WEBGPU_0;
} // namespace } // namespace
ParserImpl::ParserImpl(const std::vector<uint32_t>& spv_binary) ParserImpl::ParserImpl(const Context& ctx,
: Reader(), const std::vector<uint32_t>& spv_binary)
: Reader(ctx),
spv_binary_(spv_binary), spv_binary_(spv_binary),
fail_stream_(&success_, &errors_), fail_stream_(&success_, &errors_),
namer_(fail_stream_), namer_(fail_stream_),
@ -75,6 +76,11 @@ ParserImpl::ParserImpl(const std::vector<uint32_t>& spv_binary)
ParserImpl::~ParserImpl() = default; ParserImpl::~ParserImpl() = default;
bool ParserImpl::Parse() { bool ParserImpl::Parse() {
if (ctx_.type_mgr == nullptr) {
Fail() << "Missing type manager";
return false;
}
if (!success_) { if (!success_) {
return false; return false;
} }
@ -125,22 +131,21 @@ ast::type::Type* ParserImpl::ConvertType(uint32_t type_id) {
} }
ast::type::Type* result = nullptr; ast::type::Type* result = nullptr;
TypeManager* tint_tm = TypeManager::Instance();
switch (spirv_type->kind()) { switch (spirv_type->kind()) {
case spvtools::opt::analysis::Type::kVoid: case spvtools::opt::analysis::Type::kVoid:
result = tint_tm->Get(std::make_unique<ast::type::VoidType>()); result = ctx_.type_mgr->Get(std::make_unique<ast::type::VoidType>());
break; break;
case spvtools::opt::analysis::Type::kBool: case spvtools::opt::analysis::Type::kBool:
result = tint_tm->Get(std::make_unique<ast::type::BoolType>()); result = ctx_.type_mgr->Get(std::make_unique<ast::type::BoolType>());
break; break;
case spvtools::opt::analysis::Type::kInteger: { case spvtools::opt::analysis::Type::kInteger: {
const auto* int_ty = spirv_type->AsInteger(); const auto* int_ty = spirv_type->AsInteger();
if (int_ty->width() == 32) { if (int_ty->width() == 32) {
if (int_ty->IsSigned()) { if (int_ty->IsSigned()) {
result = tint_tm->Get(std::make_unique<ast::type::I32Type>()); result = ctx_.type_mgr->Get(std::make_unique<ast::type::I32Type>());
} else { } else {
result = tint_tm->Get(std::make_unique<ast::type::U32Type>()); result = ctx_.type_mgr->Get(std::make_unique<ast::type::U32Type>());
} }
} else { } else {
Fail() << "unhandled integer width: " << int_ty->width(); Fail() << "unhandled integer width: " << int_ty->width();
@ -150,7 +155,7 @@ ast::type::Type* ParserImpl::ConvertType(uint32_t type_id) {
case spvtools::opt::analysis::Type::kFloat: { case spvtools::opt::analysis::Type::kFloat: {
const auto* float_ty = spirv_type->AsFloat(); const auto* float_ty = spirv_type->AsFloat();
if (float_ty->width() == 32) { if (float_ty->width() == 32) {
result = tint_tm->Get(std::make_unique<ast::type::F32Type>()); result = ctx_.type_mgr->Get(std::make_unique<ast::type::F32Type>());
} else { } else {
Fail() << "unhandled float width: " << float_ty->width(); Fail() << "unhandled float width: " << float_ty->width();
} }
@ -161,7 +166,7 @@ ast::type::Type* ParserImpl::ConvertType(uint32_t type_id) {
const auto num_elem = vec_ty->element_count(); const auto num_elem = vec_ty->element_count();
auto* ast_elem_ty = ConvertType(type_mgr_->GetId(vec_ty->element_type())); auto* ast_elem_ty = ConvertType(type_mgr_->GetId(vec_ty->element_type()));
if (ast_elem_ty != nullptr) { if (ast_elem_ty != nullptr) {
result = tint_tm->Get( result = ctx_.type_mgr->Get(
std::make_unique<ast::type::VectorType>(ast_elem_ty, num_elem)); std::make_unique<ast::type::VectorType>(ast_elem_ty, num_elem));
} }
// In the error case, we'll already have emitted a diagnostic. // In the error case, we'll already have emitted a diagnostic.
@ -175,7 +180,7 @@ ast::type::Type* ParserImpl::ConvertType(uint32_t type_id) {
const auto num_columns = mat_ty->element_count(); const auto num_columns = mat_ty->element_count();
auto* ast_scalar_ty = ConvertType(type_mgr_->GetId(scalar_ty)); auto* ast_scalar_ty = ConvertType(type_mgr_->GetId(scalar_ty));
if (ast_scalar_ty != nullptr) { if (ast_scalar_ty != nullptr) {
result = tint_tm->Get(std::make_unique<ast::type::MatrixType>( result = ctx_.type_mgr->Get(std::make_unique<ast::type::MatrixType>(
ast_scalar_ty, num_rows, num_columns)); ast_scalar_ty, num_rows, num_columns));
} }
// In the error case, we'll already have emitted a diagnostic. // In the error case, we'll already have emitted a diagnostic.

View File

@ -45,8 +45,9 @@ namespace spirv {
class ParserImpl : Reader { class ParserImpl : Reader {
public: public:
/// Creates a new parser /// Creates a new parser
/// @param ctx the context object
/// @param input the input data to parse /// @param input the input data to parse
explicit ParserImpl(const std::vector<uint32_t>& input); ParserImpl(const Context& ctx, const std::vector<uint32_t>& input);
/// Destructor /// Destructor
~ParserImpl() override; ~ParserImpl() override;

View File

@ -20,6 +20,7 @@
#include "src/ast/type/matrix_type.h" #include "src/ast/type/matrix_type.h"
#include "src/ast/type/vector_type.h" #include "src/ast/type/vector_type.h"
#include "src/reader/spirv/parser_impl.h" #include "src/reader/spirv/parser_impl.h"
#include "src/reader/spirv/parser_impl_test_helper.h"
#include "src/reader/spirv/spirv_tools_helpers_test.h" #include "src/reader/spirv/spirv_tools_helpers_test.h"
#include "src/type_manager.h" #include "src/type_manager.h"
@ -30,231 +31,224 @@ namespace {
using ::testing::Eq; using ::testing::Eq;
class SpvParserTest_ConvertType : public ::testing::Test { TEST_F(SpvParserTest, ConvertType_PreservesExistingFailure) {
void TearDown() override { auto p = parser(std::vector<uint32_t>{});
// Clean up the type manager instance at the end of a single test. p->Fail() << "boing";
TypeManager::Destroy(); auto* type = p->ConvertType(10);
}
};
TEST_F(SpvParserTest_ConvertType, PreservesExistingFailure) {
ParserImpl p(std::vector<uint32_t>{});
p.Fail() << "boing";
auto* type = p.ConvertType(10);
EXPECT_EQ(type, nullptr); EXPECT_EQ(type, nullptr);
EXPECT_THAT(p.error(), Eq("boing")); EXPECT_THAT(p->error(), Eq("boing"));
} }
TEST_F(SpvParserTest_ConvertType, RequiresInternalRepresntation) { TEST_F(SpvParserTest, ConvertType_RequiresInternalRepresntation) {
ParserImpl p(std::vector<uint32_t>{}); auto p = parser(std::vector<uint32_t>{});
auto* type = p.ConvertType(10); auto* type = p->ConvertType(10);
EXPECT_EQ(type, nullptr); EXPECT_EQ(type, nullptr);
EXPECT_THAT( EXPECT_THAT(
p.error(), p->error(),
Eq("ConvertType called when the internal module has not been built")); Eq("ConvertType called when the internal module has not been built"));
} }
TEST_F(SpvParserTest_ConvertType, NotAnId) { TEST_F(SpvParserTest, ConvertType_NotAnId) {
ParserImpl p(test::Assemble("%1 = OpExtInstImport \"GLSL.std.450\"")); auto p = parser(test::Assemble("%1 = OpExtInstImport \"GLSL.std.450\""));
EXPECT_TRUE(p.BuildAndParseInternalModule()) << p.error(); EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
auto* type = p.ConvertType(10); auto* type = p->ConvertType(10);
EXPECT_EQ(type, nullptr); EXPECT_EQ(type, nullptr);
EXPECT_EQ(nullptr, type); EXPECT_EQ(nullptr, type);
EXPECT_THAT(p.error(), Eq("ID is not a SPIR-V type: 10")); EXPECT_THAT(p->error(), Eq("ID is not a SPIR-V type: 10"));
} }
TEST_F(SpvParserTest_ConvertType, IdExistsButIsNotAType) { TEST_F(SpvParserTest, ConvertType_IdExistsButIsNotAType) {
ParserImpl p(test::Assemble("%1 = OpExtInstImport \"GLSL.std.450\"")); auto p = parser(test::Assemble("%1 = OpExtInstImport \"GLSL.std.450\""));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
auto* type = p.ConvertType(1); auto* type = p->ConvertType(1);
EXPECT_EQ(nullptr, type); EXPECT_EQ(nullptr, type);
EXPECT_THAT(p.error(), Eq("ID is not a SPIR-V type: 1")); EXPECT_THAT(p->error(), Eq("ID is not a SPIR-V type: 1"));
} }
TEST_F(SpvParserTest_ConvertType, UnhandledType) { TEST_F(SpvParserTest, ConvertType_UnhandledType) {
// Pipes are an OpenCL type. Tint doesn't support them. // Pipes are an OpenCL type. Tint doesn't support them.
ParserImpl p(test::Assemble("%70 = OpTypePipe WriteOnly")); auto p = parser(test::Assemble("%70 = OpTypePipe WriteOnly"));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
auto* type = p.ConvertType(70); auto* type = p->ConvertType(70);
EXPECT_EQ(nullptr, type); EXPECT_EQ(nullptr, type);
EXPECT_THAT(p.error(), Eq("unknown SPIR-V type: 70")); EXPECT_THAT(p->error(), Eq("unknown SPIR-V type: 70"));
} }
TEST_F(SpvParserTest_ConvertType, Void) { TEST_F(SpvParserTest, ConvertType_Void) {
ParserImpl p(test::Assemble("%1 = OpTypeVoid")); auto p = parser(test::Assemble("%1 = OpTypeVoid"));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
auto* type = p.ConvertType(1); auto* type = p->ConvertType(1);
EXPECT_TRUE(type->IsVoid()); EXPECT_TRUE(type->IsVoid());
EXPECT_TRUE(p.error().empty()); EXPECT_TRUE(p->error().empty());
} }
TEST_F(SpvParserTest_ConvertType, Bool) { TEST_F(SpvParserTest, ConvertType_Bool) {
ParserImpl p(test::Assemble("%100 = OpTypeBool")); auto p = parser(test::Assemble("%100 = OpTypeBool"));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
auto* type = p.ConvertType(100); auto* type = p->ConvertType(100);
EXPECT_TRUE(type->IsBool()); EXPECT_TRUE(type->IsBool());
EXPECT_TRUE(p.error().empty()); EXPECT_TRUE(p->error().empty());
} }
TEST_F(SpvParserTest_ConvertType, I32) { TEST_F(SpvParserTest, ConvertType_I32) {
ParserImpl p(test::Assemble("%2 = OpTypeInt 32 1")); auto p = parser(test::Assemble("%2 = OpTypeInt 32 1"));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
auto* type = p.ConvertType(2); auto* type = p->ConvertType(2);
EXPECT_TRUE(type->IsI32()); EXPECT_TRUE(type->IsI32());
EXPECT_TRUE(p.error().empty()); EXPECT_TRUE(p->error().empty());
} }
TEST_F(SpvParserTest_ConvertType, U32) { TEST_F(SpvParserTest, ConvertType_U32) {
ParserImpl p(test::Assemble("%3 = OpTypeInt 32 0")); auto p = parser(test::Assemble("%3 = OpTypeInt 32 0"));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
auto* type = p.ConvertType(3); auto* type = p->ConvertType(3);
EXPECT_TRUE(type->IsU32()); EXPECT_TRUE(type->IsU32());
EXPECT_TRUE(p.error().empty()); EXPECT_TRUE(p->error().empty());
} }
TEST_F(SpvParserTest_ConvertType, F32) { TEST_F(SpvParserTest, ConvertType_F32) {
ParserImpl p(test::Assemble("%4 = OpTypeFloat 32")); auto p = parser(test::Assemble("%4 = OpTypeFloat 32"));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
auto* type = p.ConvertType(4); auto* type = p->ConvertType(4);
EXPECT_TRUE(type->IsF32()); EXPECT_TRUE(type->IsF32());
EXPECT_TRUE(p.error().empty()); EXPECT_TRUE(p->error().empty());
} }
TEST_F(SpvParserTest_ConvertType, BadIntWidth) { TEST_F(SpvParserTest, ConvertType_BadIntWidth) {
ParserImpl p(test::Assemble("%5 = OpTypeInt 17 1")); auto p = parser(test::Assemble("%5 = OpTypeInt 17 1"));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
auto* type = p.ConvertType(5); auto* type = p->ConvertType(5);
EXPECT_EQ(type, nullptr); EXPECT_EQ(type, nullptr);
EXPECT_THAT(p.error(), Eq("unhandled integer width: 17")); EXPECT_THAT(p->error(), Eq("unhandled integer width: 17"));
} }
TEST_F(SpvParserTest_ConvertType, BadFloatWidth) { TEST_F(SpvParserTest, ConvertType_BadFloatWidth) {
ParserImpl p(test::Assemble("%6 = OpTypeFloat 19")); auto p = parser(test::Assemble("%6 = OpTypeFloat 19"));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
auto* type = p.ConvertType(6); auto* type = p->ConvertType(6);
EXPECT_EQ(type, nullptr); EXPECT_EQ(type, nullptr);
EXPECT_THAT(p.error(), Eq("unhandled float width: 19")); EXPECT_THAT(p->error(), Eq("unhandled float width: 19"));
} }
TEST_F(SpvParserTest_ConvertType, InvalidVectorElement) { TEST_F(SpvParserTest, DISABLED_ConvertType_InvalidVectorElement) {
ParserImpl p(test::Assemble(R"( auto p = parser(test::Assemble(R"(
%5 = OpTypePipe ReadOnly %5 = OpTypePipe ReadOnly
%20 = OpTypeVector %5 2 %20 = OpTypeVector %5 2
)")); )"));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
auto* type = p.ConvertType(20); auto* type = p->ConvertType(20);
EXPECT_EQ(type, nullptr); EXPECT_EQ(type, nullptr);
EXPECT_THAT(p.error(), Eq("unknown SPIR-V type: 5")); EXPECT_THAT(p->error(), Eq("unknown SPIR-V type: 5"));
} }
TEST_F(SpvParserTest_ConvertType, VecOverF32) { TEST_F(SpvParserTest, ConvertType_VecOverF32) {
ParserImpl p(test::Assemble(R"( auto p = parser(test::Assemble(R"(
%float = OpTypeFloat 32 %float = OpTypeFloat 32
%20 = OpTypeVector %float 2 %20 = OpTypeVector %float 2
%30 = OpTypeVector %float 3 %30 = OpTypeVector %float 3
%40 = OpTypeVector %float 4 %40 = OpTypeVector %float 4
)")); )"));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
auto* v2xf32 = p.ConvertType(20); auto* v2xf32 = p->ConvertType(20);
EXPECT_TRUE(v2xf32->IsVector()); EXPECT_TRUE(v2xf32->IsVector());
EXPECT_TRUE(v2xf32->AsVector()->type()->IsF32()); EXPECT_TRUE(v2xf32->AsVector()->type()->IsF32());
EXPECT_EQ(v2xf32->AsVector()->size(), 2u); EXPECT_EQ(v2xf32->AsVector()->size(), 2u);
auto* v3xf32 = p.ConvertType(30); auto* v3xf32 = p->ConvertType(30);
EXPECT_TRUE(v3xf32->IsVector()); EXPECT_TRUE(v3xf32->IsVector());
EXPECT_TRUE(v3xf32->AsVector()->type()->IsF32()); EXPECT_TRUE(v3xf32->AsVector()->type()->IsF32());
EXPECT_EQ(v3xf32->AsVector()->size(), 3u); EXPECT_EQ(v3xf32->AsVector()->size(), 3u);
auto* v4xf32 = p.ConvertType(40); auto* v4xf32 = p->ConvertType(40);
EXPECT_TRUE(v4xf32->IsVector()); EXPECT_TRUE(v4xf32->IsVector());
EXPECT_TRUE(v4xf32->AsVector()->type()->IsF32()); EXPECT_TRUE(v4xf32->AsVector()->type()->IsF32());
EXPECT_EQ(v4xf32->AsVector()->size(), 4u); EXPECT_EQ(v4xf32->AsVector()->size(), 4u);
EXPECT_TRUE(p.error().empty()); EXPECT_TRUE(p->error().empty());
} }
TEST_F(SpvParserTest_ConvertType, VecOverI32) { TEST_F(SpvParserTest, ConvertType_VecOverI32) {
ParserImpl p(test::Assemble(R"( auto p = parser(test::Assemble(R"(
%int = OpTypeInt 32 1 %int = OpTypeInt 32 1
%20 = OpTypeVector %int 2 %20 = OpTypeVector %int 2
%30 = OpTypeVector %int 3 %30 = OpTypeVector %int 3
%40 = OpTypeVector %int 4 %40 = OpTypeVector %int 4
)")); )"));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
auto* v2xi32 = p.ConvertType(20); auto* v2xi32 = p->ConvertType(20);
EXPECT_TRUE(v2xi32->IsVector()); EXPECT_TRUE(v2xi32->IsVector());
EXPECT_TRUE(v2xi32->AsVector()->type()->IsI32()); EXPECT_TRUE(v2xi32->AsVector()->type()->IsI32());
EXPECT_EQ(v2xi32->AsVector()->size(), 2u); EXPECT_EQ(v2xi32->AsVector()->size(), 2u);
auto* v3xi32 = p.ConvertType(30); auto* v3xi32 = p->ConvertType(30);
EXPECT_TRUE(v3xi32->IsVector()); EXPECT_TRUE(v3xi32->IsVector());
EXPECT_TRUE(v3xi32->AsVector()->type()->IsI32()); EXPECT_TRUE(v3xi32->AsVector()->type()->IsI32());
EXPECT_EQ(v3xi32->AsVector()->size(), 3u); EXPECT_EQ(v3xi32->AsVector()->size(), 3u);
auto* v4xi32 = p.ConvertType(40); auto* v4xi32 = p->ConvertType(40);
EXPECT_TRUE(v4xi32->IsVector()); EXPECT_TRUE(v4xi32->IsVector());
EXPECT_TRUE(v4xi32->AsVector()->type()->IsI32()); EXPECT_TRUE(v4xi32->AsVector()->type()->IsI32());
EXPECT_EQ(v4xi32->AsVector()->size(), 4u); EXPECT_EQ(v4xi32->AsVector()->size(), 4u);
EXPECT_TRUE(p.error().empty()); EXPECT_TRUE(p->error().empty());
} }
TEST_F(SpvParserTest_ConvertType, VecOverU32) { TEST_F(SpvParserTest, ConvertType_VecOverU32) {
ParserImpl p(test::Assemble(R"( auto p = parser(test::Assemble(R"(
%uint = OpTypeInt 32 0 %uint = OpTypeInt 32 0
%20 = OpTypeVector %uint 2 %20 = OpTypeVector %uint 2
%30 = OpTypeVector %uint 3 %30 = OpTypeVector %uint 3
%40 = OpTypeVector %uint 4 %40 = OpTypeVector %uint 4
)")); )"));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
auto* v2xu32 = p.ConvertType(20); auto* v2xu32 = p->ConvertType(20);
EXPECT_TRUE(v2xu32->IsVector()); EXPECT_TRUE(v2xu32->IsVector());
EXPECT_TRUE(v2xu32->AsVector()->type()->IsU32()); EXPECT_TRUE(v2xu32->AsVector()->type()->IsU32());
EXPECT_EQ(v2xu32->AsVector()->size(), 2u); EXPECT_EQ(v2xu32->AsVector()->size(), 2u);
auto* v3xu32 = p.ConvertType(30); auto* v3xu32 = p->ConvertType(30);
EXPECT_TRUE(v3xu32->IsVector()); EXPECT_TRUE(v3xu32->IsVector());
EXPECT_TRUE(v3xu32->AsVector()->type()->IsU32()); EXPECT_TRUE(v3xu32->AsVector()->type()->IsU32());
EXPECT_EQ(v3xu32->AsVector()->size(), 3u); EXPECT_EQ(v3xu32->AsVector()->size(), 3u);
auto* v4xu32 = p.ConvertType(40); auto* v4xu32 = p->ConvertType(40);
EXPECT_TRUE(v4xu32->IsVector()); EXPECT_TRUE(v4xu32->IsVector());
EXPECT_TRUE(v4xu32->AsVector()->type()->IsU32()); EXPECT_TRUE(v4xu32->AsVector()->type()->IsU32());
EXPECT_EQ(v4xu32->AsVector()->size(), 4u); EXPECT_EQ(v4xu32->AsVector()->size(), 4u);
EXPECT_TRUE(p.error().empty()); EXPECT_TRUE(p->error().empty());
} }
TEST_F(SpvParserTest_ConvertType, InvalidMatrixElement) { TEST_F(SpvParserTest, DISABLED_ConvertType_InvalidMatrixElement) {
ParserImpl p(test::Assemble(R"( auto p = parser(test::Assemble(R"(
%5 = OpTypePipe ReadOnly %5 = OpTypePipe ReadOnly
%10 = OpTypeVector %5 2 %10 = OpTypeVector %5 2
%20 = OpTypeMatrix %10 2 %20 = OpTypeMatrix %10 2
)")); )"));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
auto* type = p.ConvertType(20); auto* type = p->ConvertType(20);
EXPECT_EQ(type, nullptr); EXPECT_EQ(type, nullptr);
EXPECT_THAT(p.error(), Eq("unknown SPIR-V type: 5")); EXPECT_THAT(p->error(), Eq("unknown SPIR-V type: 5"));
} }
TEST_F(SpvParserTest_ConvertType, MatrixOverF32) { TEST_F(SpvParserTest, ConvertType_MatrixOverF32) {
// Matrices are only defined over floats. // Matrices are only defined over floats.
ParserImpl p(test::Assemble(R"( auto p = parser(test::Assemble(R"(
%float = OpTypeFloat 32 %float = OpTypeFloat 32
%v2 = OpTypeVector %float 2 %v2 = OpTypeVector %float 2
%v3 = OpTypeVector %float 3 %v3 = OpTypeVector %float 3
@ -271,63 +265,63 @@ TEST_F(SpvParserTest_ConvertType, MatrixOverF32) {
%43 = OpTypeMatrix %v4 3 %43 = OpTypeMatrix %v4 3
%44 = OpTypeMatrix %v4 4 %44 = OpTypeMatrix %v4 4
)")); )"));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
auto* m22 = p.ConvertType(22); auto* m22 = p->ConvertType(22);
EXPECT_TRUE(m22->IsMatrix()); EXPECT_TRUE(m22->IsMatrix());
EXPECT_TRUE(m22->AsMatrix()->type()->IsF32()); EXPECT_TRUE(m22->AsMatrix()->type()->IsF32());
EXPECT_EQ(m22->AsMatrix()->rows(), 2); EXPECT_EQ(m22->AsMatrix()->rows(), 2);
EXPECT_EQ(m22->AsMatrix()->columns(), 2); EXPECT_EQ(m22->AsMatrix()->columns(), 2);
auto* m23 = p.ConvertType(23); auto* m23 = p->ConvertType(23);
EXPECT_TRUE(m23->IsMatrix()); EXPECT_TRUE(m23->IsMatrix());
EXPECT_TRUE(m23->AsMatrix()->type()->IsF32()); EXPECT_TRUE(m23->AsMatrix()->type()->IsF32());
EXPECT_EQ(m23->AsMatrix()->rows(), 2); EXPECT_EQ(m23->AsMatrix()->rows(), 2);
EXPECT_EQ(m23->AsMatrix()->columns(), 3); EXPECT_EQ(m23->AsMatrix()->columns(), 3);
auto* m24 = p.ConvertType(24); auto* m24 = p->ConvertType(24);
EXPECT_TRUE(m24->IsMatrix()); EXPECT_TRUE(m24->IsMatrix());
EXPECT_TRUE(m24->AsMatrix()->type()->IsF32()); EXPECT_TRUE(m24->AsMatrix()->type()->IsF32());
EXPECT_EQ(m24->AsMatrix()->rows(), 2); EXPECT_EQ(m24->AsMatrix()->rows(), 2);
EXPECT_EQ(m24->AsMatrix()->columns(), 4); EXPECT_EQ(m24->AsMatrix()->columns(), 4);
auto* m32 = p.ConvertType(32); auto* m32 = p->ConvertType(32);
EXPECT_TRUE(m32->IsMatrix()); EXPECT_TRUE(m32->IsMatrix());
EXPECT_TRUE(m32->AsMatrix()->type()->IsF32()); EXPECT_TRUE(m32->AsMatrix()->type()->IsF32());
EXPECT_EQ(m32->AsMatrix()->rows(), 3); EXPECT_EQ(m32->AsMatrix()->rows(), 3);
EXPECT_EQ(m32->AsMatrix()->columns(), 2); EXPECT_EQ(m32->AsMatrix()->columns(), 2);
auto* m33 = p.ConvertType(33); auto* m33 = p->ConvertType(33);
EXPECT_TRUE(m33->IsMatrix()); EXPECT_TRUE(m33->IsMatrix());
EXPECT_TRUE(m33->AsMatrix()->type()->IsF32()); EXPECT_TRUE(m33->AsMatrix()->type()->IsF32());
EXPECT_EQ(m33->AsMatrix()->rows(), 3); EXPECT_EQ(m33->AsMatrix()->rows(), 3);
EXPECT_EQ(m33->AsMatrix()->columns(), 3); EXPECT_EQ(m33->AsMatrix()->columns(), 3);
auto* m34 = p.ConvertType(34); auto* m34 = p->ConvertType(34);
EXPECT_TRUE(m34->IsMatrix()); EXPECT_TRUE(m34->IsMatrix());
EXPECT_TRUE(m34->AsMatrix()->type()->IsF32()); EXPECT_TRUE(m34->AsMatrix()->type()->IsF32());
EXPECT_EQ(m34->AsMatrix()->rows(), 3); EXPECT_EQ(m34->AsMatrix()->rows(), 3);
EXPECT_EQ(m34->AsMatrix()->columns(), 4); EXPECT_EQ(m34->AsMatrix()->columns(), 4);
auto* m42 = p.ConvertType(42); auto* m42 = p->ConvertType(42);
EXPECT_TRUE(m42->IsMatrix()); EXPECT_TRUE(m42->IsMatrix());
EXPECT_TRUE(m42->AsMatrix()->type()->IsF32()); EXPECT_TRUE(m42->AsMatrix()->type()->IsF32());
EXPECT_EQ(m42->AsMatrix()->rows(), 4); EXPECT_EQ(m42->AsMatrix()->rows(), 4);
EXPECT_EQ(m42->AsMatrix()->columns(), 2); EXPECT_EQ(m42->AsMatrix()->columns(), 2);
auto* m43 = p.ConvertType(43); auto* m43 = p->ConvertType(43);
EXPECT_TRUE(m43->IsMatrix()); EXPECT_TRUE(m43->IsMatrix());
EXPECT_TRUE(m43->AsMatrix()->type()->IsF32()); EXPECT_TRUE(m43->AsMatrix()->type()->IsF32());
EXPECT_EQ(m43->AsMatrix()->rows(), 4); EXPECT_EQ(m43->AsMatrix()->rows(), 4);
EXPECT_EQ(m43->AsMatrix()->columns(), 3); EXPECT_EQ(m43->AsMatrix()->columns(), 3);
auto* m44 = p.ConvertType(44); auto* m44 = p->ConvertType(44);
EXPECT_TRUE(m44->IsMatrix()); EXPECT_TRUE(m44->IsMatrix());
EXPECT_TRUE(m44->AsMatrix()->type()->IsF32()); EXPECT_TRUE(m44->AsMatrix()->type()->IsF32());
EXPECT_EQ(m44->AsMatrix()->rows(), 4); EXPECT_EQ(m44->AsMatrix()->rows(), 4);
EXPECT_EQ(m44->AsMatrix()->columns(), 4); EXPECT_EQ(m44->AsMatrix()->columns(), 4);
EXPECT_TRUE(p.error().empty()); EXPECT_TRUE(p->error().empty());
} }
} // namespace } // namespace

View File

@ -16,6 +16,7 @@
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "src/reader/spirv/parser_impl.h" #include "src/reader/spirv/parser_impl.h"
#include "src/reader/spirv/parser_impl_test_helper.h"
#include "src/reader/spirv/spirv_tools_helpers_test.h" #include "src/reader/spirv/spirv_tools_helpers_test.h"
namespace tint { namespace tint {
@ -25,8 +26,6 @@ namespace {
using ::testing::HasSubstr; using ::testing::HasSubstr;
using SpvParserTest_EntryPoint = ::testing::Test;
std::string MakeEntryPoint(const std::string& stage, std::string MakeEntryPoint(const std::string& stage,
const std::string& name, const std::string& name,
const std::string& id = "42") { const std::string& id = "42") {
@ -35,55 +34,55 @@ std::string MakeEntryPoint(const std::string& stage,
"%" + id + " = OpTypeVoid\n"; "%" + id + " = OpTypeVoid\n";
} }
TEST_F(SpvParserTest_EntryPoint, NoEntryPoint) { TEST_F(SpvParserTest, EntryPoint_NoEntryPoint) {
ParserImpl p(test::Assemble("")); auto p = parser(test::Assemble(""));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
EXPECT_TRUE(p.error().empty()); EXPECT_TRUE(p->error().empty());
const auto module_ast = p.module().to_str(); const auto module_ast = p->module().to_str();
EXPECT_THAT(module_ast, Not(HasSubstr("EntryPoint"))); EXPECT_THAT(module_ast, Not(HasSubstr("EntryPoint")));
} }
TEST_F(SpvParserTest_EntryPoint, Vertex) { TEST_F(SpvParserTest, EntryPoint_Vertex) {
ParserImpl p(test::Assemble(MakeEntryPoint("Vertex", "foobar"))); auto p = parser(test::Assemble(MakeEntryPoint("Vertex", "foobar")));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
EXPECT_TRUE(p.error().empty()); EXPECT_TRUE(p->error().empty());
const auto module_str = p.module().to_str(); const auto module_str = p->module().to_str();
EXPECT_THAT(module_str, HasSubstr(R"(EntryPoint{vertex = foobar})")); EXPECT_THAT(module_str, HasSubstr(R"(EntryPoint{vertex = foobar})"));
} }
TEST_F(SpvParserTest_EntryPoint, Fragment) { TEST_F(SpvParserTest, EntryPoint_Fragment) {
ParserImpl p(test::Assemble(MakeEntryPoint("Fragment", "blitz"))); auto p = parser(test::Assemble(MakeEntryPoint("Fragment", "blitz")));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
EXPECT_TRUE(p.error().empty()); EXPECT_TRUE(p->error().empty());
const auto module_str = p.module().to_str(); const auto module_str = p->module().to_str();
EXPECT_THAT(module_str, HasSubstr(R"(EntryPoint{fragment = blitz})")); EXPECT_THAT(module_str, HasSubstr(R"(EntryPoint{fragment = blitz})"));
} }
TEST_F(SpvParserTest_EntryPoint, Compute) { TEST_F(SpvParserTest, EntryPoint_Compute) {
ParserImpl p(test::Assemble(MakeEntryPoint("GLCompute", "sort"))); auto p = parser(test::Assemble(MakeEntryPoint("GLCompute", "sort")));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
EXPECT_TRUE(p.error().empty()); EXPECT_TRUE(p->error().empty());
const auto module_str = p.module().to_str(); const auto module_str = p->module().to_str();
EXPECT_THAT(module_str, HasSubstr(R"(EntryPoint{compute = sort})")); EXPECT_THAT(module_str, HasSubstr(R"(EntryPoint{compute = sort})"));
} }
TEST_F(SpvParserTest_EntryPoint, MultiNameConflict) { TEST_F(SpvParserTest, EntryPoint_MultiNameConflict) {
ParserImpl p(test::Assemble(MakeEntryPoint("GLCompute", "work", "40") + auto p = parser(test::Assemble(MakeEntryPoint("GLCompute", "work", "40") +
MakeEntryPoint("Vertex", "work", "50") + MakeEntryPoint("Vertex", "work", "50") +
MakeEntryPoint("Fragment", "work", "60"))); MakeEntryPoint("Fragment", "work", "60")));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
EXPECT_TRUE(p.error().empty()); EXPECT_TRUE(p->error().empty());
const auto module_str = p.module().to_str(); const auto module_str = p->module().to_str();
EXPECT_THAT(module_str, HasSubstr(R"(EntryPoint{compute = work})")); EXPECT_THAT(module_str, HasSubstr(R"(EntryPoint{compute = work})"));
EXPECT_THAT(module_str, HasSubstr(R"(EntryPoint{vertex = work_1})")); EXPECT_THAT(module_str, HasSubstr(R"(EntryPoint{vertex = work_1})"));
EXPECT_THAT(module_str, HasSubstr(R"(EntryPoint{fragment = work_2})")); EXPECT_THAT(module_str, HasSubstr(R"(EntryPoint{fragment = work_2})"));
} }
TEST_F(SpvParserTest_EntryPoint, NameIsSanitized) { TEST_F(SpvParserTest, EntryPoint_NameIsSanitized) {
ParserImpl p(test::Assemble(MakeEntryPoint("GLCompute", ".1234"))); auto p = parser(test::Assemble(MakeEntryPoint("GLCompute", ".1234")));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
EXPECT_TRUE(p.error().empty()); EXPECT_TRUE(p->error().empty());
const auto module_str = p.module().to_str(); const auto module_str = p->module().to_str();
EXPECT_THAT(module_str, HasSubstr(R"(EntryPoint{compute = x_1234})")); EXPECT_THAT(module_str, HasSubstr(R"(EntryPoint{compute = x_1234})"));
} }

View File

@ -17,6 +17,7 @@
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "src/reader/spirv/parser_impl.h" #include "src/reader/spirv/parser_impl.h"
#include "src/reader/spirv/parser_impl_test_helper.h"
#include "src/reader/spirv/spirv_tools_helpers_test.h" #include "src/reader/spirv/spirv_tools_helpers_test.h"
namespace tint { namespace tint {
@ -30,34 +31,32 @@ using ::testing::HasSubstr;
using ::testing::Not; using ::testing::Not;
using ::testing::UnorderedElementsAre; using ::testing::UnorderedElementsAre;
using SpvParseImport = ::testing::Test; TEST_F(SpvParserTest, Import_NoImport) {
auto p = parser(test::Assemble("%1 = OpTypeVoid"));
TEST_F(SpvParseImport, NoImport) { EXPECT_TRUE(p->BuildAndParseInternalModule());
ParserImpl p(test::Assemble("%1 = OpTypeVoid")); EXPECT_TRUE(p->error().empty());
EXPECT_TRUE(p.BuildAndParseInternalModule()); const auto module_ast = p->module().to_str();
EXPECT_TRUE(p.error().empty());
const auto module_ast = p.module().to_str();
EXPECT_THAT(module_ast, Not(HasSubstr("Import"))); EXPECT_THAT(module_ast, Not(HasSubstr("Import")));
} }
TEST_F(SpvParseImport, ImportGlslStd450) { TEST_F(SpvParserTest, Import_ImportGlslStd450) {
ParserImpl p(test::Assemble(R"(%1 = OpExtInstImport "GLSL.std.450")")); auto p = parser(test::Assemble(R"(%1 = OpExtInstImport "GLSL.std.450")"));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
EXPECT_TRUE(p.error().empty()); EXPECT_TRUE(p->error().empty());
EXPECT_THAT(p.glsl_std_450_imports(), ElementsAre(1)); EXPECT_THAT(p->glsl_std_450_imports(), ElementsAre(1));
const auto module_ast = p.module().to_str(); const auto module_ast = p->module().to_str();
EXPECT_THAT(module_ast, HasSubstr(R"(Import{"GLSL.std.450" as std::glsl})")); EXPECT_THAT(module_ast, HasSubstr(R"(Import{"GLSL.std.450" as std::glsl})"));
} }
TEST_F(SpvParseImport, ImportGlslStd450Twice) { TEST_F(SpvParserTest, Import_ImportGlslStd450Twice) {
ParserImpl p(test::Assemble(R"( auto p = parser(test::Assemble(R"(
%1 = OpExtInstImport "GLSL.std.450" %1 = OpExtInstImport "GLSL.std.450"
%42 = OpExtInstImport "GLSL.std.450" %42 = OpExtInstImport "GLSL.std.450"
)")); )"));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
EXPECT_TRUE(p.error().empty()); EXPECT_TRUE(p->error().empty());
EXPECT_THAT(p.glsl_std_450_imports(), UnorderedElementsAre(1, 42)); EXPECT_THAT(p->glsl_std_450_imports(), UnorderedElementsAre(1, 42));
const auto module = p.module(); const auto module = p->module();
EXPECT_EQ(module.imports().size(), 1); EXPECT_EQ(module.imports().size(), 1);
const auto module_ast = module.to_str(); const auto module_ast = module.to_str();
// TODO(dneto): Use a matcher to show there is only one import. // TODO(dneto): Use a matcher to show there is only one import.

View File

@ -18,6 +18,7 @@
#include <vector> #include <vector>
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "src/reader/spirv/parser_impl_test_helper.h"
#include "src/reader/spirv/spirv_tools_helpers_test.h" #include "src/reader/spirv/spirv_tools_helpers_test.h"
namespace tint { namespace tint {
@ -28,23 +29,21 @@ namespace {
using ::testing::HasSubstr; using ::testing::HasSubstr;
using SpvParserImplTest = testing::Test; TEST_F(SpvParserTest, Impl_Uint32VecEmpty) {
TEST_F(SpvParserImplTest, Uint32VecEmpty) {
std::vector<uint32_t> data; std::vector<uint32_t> data;
ParserImpl p{data}; auto p = parser(data);
EXPECT_FALSE(p.Parse()); EXPECT_FALSE(p->Parse());
// TODO(dneto): What message? // TODO(dneto): What message?
} }
TEST_F(SpvParserImplTest, InvalidModuleFails) { TEST_F(SpvParserTest, Impl_InvalidModuleFails) {
auto invalid_spv = test::Assemble("%ty = OpTypeInt 3 0"); auto invalid_spv = test::Assemble("%ty = OpTypeInt 3 0");
ParserImpl p{invalid_spv}; auto p = parser(invalid_spv);
EXPECT_FALSE(p.Parse()); EXPECT_FALSE(p->Parse());
EXPECT_THAT( EXPECT_THAT(
p.error(), p->error(),
HasSubstr("TypeInt cannot appear before the memory model instruction")); HasSubstr("TypeInt cannot appear before the memory model instruction"));
EXPECT_THAT(p.error(), HasSubstr("OpTypeInt 3 0")); EXPECT_THAT(p->error(), HasSubstr("OpTypeInt 3 0"));
} }
// TODO(dneto): uint32 vec, valid SPIR-V // TODO(dneto): uint32 vec, valid SPIR-V

View File

@ -0,0 +1,56 @@
// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_READER_SPIRV_PARSER_IMPL_TEST_HELPER_H_
#define SRC_READER_SPIRV_PARSER_IMPL_TEST_HELPER_H_
#include <memory>
#include <string>
#include "gtest/gtest.h"
#include "src/context.h"
#include "src/reader/spirv/parser_impl.h"
namespace tint {
namespace reader {
namespace spirv {
class SpvParserTest : public testing::Test {
public:
SpvParserTest() = default;
~SpvParserTest() = default;
void SetUp() { ctx_.type_mgr = &tm_; }
void TearDown() {
impl_ = nullptr;
ctx_.type_mgr = nullptr;
}
ParserImpl* parser(const std::vector<uint32_t>& input) {
impl_ = std::make_unique<ParserImpl>(ctx_, input);
return impl_.get();
}
private:
std::unique_ptr<ParserImpl> impl_;
Context ctx_;
TypeManager tm_;
};
} // namespace spirv
} // namespace reader
} // namespace tint
#endif // SRC_READER_WGSL_PARSER_IMPL_TEST_HELPER_H_

View File

@ -17,6 +17,7 @@
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "src/reader/spirv/parser_impl.h" #include "src/reader/spirv/parser_impl.h"
#include "src/reader/spirv/parser_impl_test_helper.h"
#include "src/reader/spirv/spirv_tools_helpers_test.h" #include "src/reader/spirv/spirv_tools_helpers_test.h"
namespace tint { namespace tint {
@ -26,64 +27,62 @@ namespace {
using ::testing::Eq; using ::testing::Eq;
using SpvParseUserNameTest = ::testing::Test; TEST_F(SpvParserTest, UserName_RespectOpName) {
auto p = parser(test::Assemble(R"(
TEST_F(SpvParseUserNameTest, RespectOpName) {
ParserImpl p(test::Assemble(R"(
OpName %1 "the_void_type" OpName %1 "the_void_type"
%1 = OpTypeVoid %1 = OpTypeVoid
)")); )"));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
EXPECT_THAT(p.namer().GetName(1), Eq("the_void_type")); EXPECT_THAT(p->namer().GetName(1), Eq("the_void_type"));
} }
TEST_F(SpvParseUserNameTest, DistinguishDuplicateSuggestion) { TEST_F(SpvParserTest, UserName_DistinguishDuplicateSuggestion) {
ParserImpl p(test::Assemble(R"( auto p = parser(test::Assemble(R"(
OpName %1 "vanilla" OpName %1 "vanilla"
OpName %2 "vanilla" OpName %2 "vanilla"
%1 = OpTypeVoid %1 = OpTypeVoid
%2 = OpTypeInt 32 0 %2 = OpTypeInt 32 0
)")); )"));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
EXPECT_THAT(p.namer().GetName(1), Eq("vanilla")); EXPECT_THAT(p->namer().GetName(1), Eq("vanilla"));
EXPECT_THAT(p.namer().GetName(2), Eq("vanilla_1")); EXPECT_THAT(p->namer().GetName(2), Eq("vanilla_1"));
} }
TEST_F(SpvParseUserNameTest, RespectOpMemberName) { TEST_F(SpvParserTest, UserName_RespectOpMemberName) {
ParserImpl p(test::Assemble(R"( auto p = parser(test::Assemble(R"(
OpMemberName %3 0 "strawberry" OpMemberName %3 0 "strawberry"
OpMemberName %3 1 "vanilla" OpMemberName %3 1 "vanilla"
OpMemberName %3 2 "chocolate" OpMemberName %3 2 "chocolate"
%2 = OpTypeInt 32 0 %2 = OpTypeInt 32 0
%3 = OpTypeStruct %2 %2 %2 %3 = OpTypeStruct %2 %2 %2
)")); )"));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
EXPECT_THAT(p.namer().GetMemberName(3, 0), Eq("strawberry")); EXPECT_THAT(p->namer().GetMemberName(3, 0), Eq("strawberry"));
EXPECT_THAT(p.namer().GetMemberName(3, 1), Eq("vanilla")); EXPECT_THAT(p->namer().GetMemberName(3, 1), Eq("vanilla"));
EXPECT_THAT(p.namer().GetMemberName(3, 2), Eq("chocolate")); EXPECT_THAT(p->namer().GetMemberName(3, 2), Eq("chocolate"));
} }
TEST_F(SpvParseUserNameTest, SynthesizeMemberNames) { TEST_F(SpvParserTest, UserName_SynthesizeMemberNames) {
ParserImpl p(test::Assemble(R"( auto p = parser(test::Assemble(R"(
%2 = OpTypeInt 32 0 %2 = OpTypeInt 32 0
%3 = OpTypeStruct %2 %2 %2 %3 = OpTypeStruct %2 %2 %2
)")); )"));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
EXPECT_THAT(p.namer().GetMemberName(3, 0), Eq("field0")); EXPECT_THAT(p->namer().GetMemberName(3, 0), Eq("field0"));
EXPECT_THAT(p.namer().GetMemberName(3, 1), Eq("field1")); EXPECT_THAT(p->namer().GetMemberName(3, 1), Eq("field1"));
EXPECT_THAT(p.namer().GetMemberName(3, 2), Eq("field2")); EXPECT_THAT(p->namer().GetMemberName(3, 2), Eq("field2"));
} }
TEST_F(SpvParseUserNameTest, MemberNamesMixUserAndSynthesized) { TEST_F(SpvParserTest, UserName_MemberNamesMixUserAndSynthesized) {
ParserImpl p(test::Assemble(R"( auto p = parser(test::Assemble(R"(
OpMemberName %3 1 "vanilla" OpMemberName %3 1 "vanilla"
%2 = OpTypeInt 32 0 %2 = OpTypeInt 32 0
%3 = OpTypeStruct %2 %2 %2 %3 = OpTypeStruct %2 %2 %2
)")); )"));
EXPECT_TRUE(p.BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule());
EXPECT_THAT(p.namer().GetMemberName(3, 0), Eq("field0")); EXPECT_THAT(p->namer().GetMemberName(3, 0), Eq("field0"));
EXPECT_THAT(p.namer().GetMemberName(3, 1), Eq("vanilla")); EXPECT_THAT(p->namer().GetMemberName(3, 1), Eq("vanilla"));
EXPECT_THAT(p.namer().GetMemberName(3, 2), Eq("field2")); EXPECT_THAT(p->namer().GetMemberName(3, 2), Eq("field2"));
} }
} // namespace } // namespace

View File

@ -18,6 +18,7 @@
#include <vector> #include <vector>
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/context.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
@ -28,7 +29,8 @@ using ParserTest = testing::Test;
TEST_F(ParserTest, Uint32VecEmpty) { TEST_F(ParserTest, Uint32VecEmpty) {
std::vector<uint32_t> data; std::vector<uint32_t> data;
Parser p{data}; Context ctx;
Parser p(ctx, data);
EXPECT_FALSE(p.Parse()); EXPECT_FALSE(p.Parse());
// TODO(dneto): What message? // TODO(dneto): What message?
} }

View File

@ -20,8 +20,8 @@ namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
Parser::Parser(const std::string& input) Parser::Parser(const Context& ctx, const std::string& input)
: Reader(), impl_(std::make_unique<ParserImpl>(input)) {} : Reader(ctx), impl_(std::make_unique<ParserImpl>(ctx, input)) {}
Parser::~Parser() = default; Parser::~Parser() = default;

View File

@ -30,8 +30,9 @@ class ParserImpl;
class Parser : public Reader { class Parser : public Reader {
public: public:
/// Creates a new parser /// Creates a new parser
/// @param ctx the context object
/// @param input the input string to parse /// @param input the input string to parse
explicit Parser(const std::string& input); Parser(const Context& ctx, const std::string& input);
~Parser() override; ~Parser() override;
/// Run the parser /// Run the parser

View File

@ -71,8 +71,8 @@ namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
ParserImpl::ParserImpl(const std::string& input) ParserImpl::ParserImpl(const Context& ctx, const std::string& input)
: lexer_(std::make_unique<Lexer>(input)) {} : ctx_(ctx), lexer_(std::make_unique<Lexer>(input)) {}
ParserImpl::~ParserImpl() = default; ParserImpl::~ParserImpl() = default;
@ -134,6 +134,11 @@ ast::type::Type* ParserImpl::get_alias(const std::string& name) {
} }
bool ParserImpl::Parse() { bool ParserImpl::Parse() {
if (ctx_.type_mgr == nullptr) {
set_error(peek(), "missing type manager");
return false;
}
translation_unit(); translation_unit();
return !has_error(); return !has_error();
} }
@ -672,8 +677,6 @@ ast::type::AliasType* ParserImpl::type_alias() {
return nullptr; return nullptr;
} }
auto tm = TypeManager::Instance();
auto type = type_decl(); auto type = type_decl();
if (has_error()) if (has_error())
return nullptr; return nullptr;
@ -687,14 +690,15 @@ ast::type::AliasType* ParserImpl::type_alias() {
} }
str->set_name(name); str->set_name(name);
type = tm->Get(std::move(str)); type = ctx_.type_mgr->Get(std::move(str));
} }
if (type == nullptr) { if (type == nullptr) {
set_error(peek(), "invalid type for alias"); set_error(peek(), "invalid type for alias");
return nullptr; return nullptr;
} }
auto alias = tm->Get(std::make_unique<ast::type::AliasType>(name, type)); auto alias =
ctx_.type_mgr->Get(std::make_unique<ast::type::AliasType>(name, type));
register_alias(name, alias); register_alias(name, alias);
return alias->AsAlias(); return alias->AsAlias();
@ -722,8 +726,6 @@ ast::type::AliasType* ParserImpl::type_alias() {
// | MAT4x3 LESS_THAN type_decl GREATER_THAN // | MAT4x3 LESS_THAN type_decl GREATER_THAN
// | MAT4x4 LESS_THAN type_decl GREATER_THAN // | MAT4x4 LESS_THAN type_decl GREATER_THAN
ast::type::Type* ParserImpl::type_decl() { ast::type::Type* ParserImpl::type_decl() {
auto tm = TypeManager::Instance();
auto t = peek(); auto t = peek();
if (t.IsIdentifier()) { if (t.IsIdentifier()) {
next(); // Consume the peek next(); // Consume the peek
@ -736,19 +738,19 @@ ast::type::Type* ParserImpl::type_decl() {
} }
if (t.IsBool()) { if (t.IsBool()) {
next(); // Consume the peek next(); // Consume the peek
return tm->Get(std::make_unique<ast::type::BoolType>()); return ctx_.type_mgr->Get(std::make_unique<ast::type::BoolType>());
} }
if (t.IsF32()) { if (t.IsF32()) {
next(); // Consume the peek next(); // Consume the peek
return tm->Get(std::make_unique<ast::type::F32Type>()); return ctx_.type_mgr->Get(std::make_unique<ast::type::F32Type>());
} }
if (t.IsI32()) { if (t.IsI32()) {
next(); // Consume the peek next(); // Consume the peek
return tm->Get(std::make_unique<ast::type::I32Type>()); return ctx_.type_mgr->Get(std::make_unique<ast::type::I32Type>());
} }
if (t.IsU32()) { if (t.IsU32()) {
next(); // Consume the peek next(); // Consume the peek
return tm->Get(std::make_unique<ast::type::U32Type>()); return ctx_.type_mgr->Get(std::make_unique<ast::type::U32Type>());
} }
if (t.IsVec2() || t.IsVec3() || t.IsVec4()) { if (t.IsVec2() || t.IsVec3() || t.IsVec4()) {
return type_decl_vector(t); return type_decl_vector(t);
@ -804,7 +806,7 @@ ast::type::Type* ParserImpl::type_decl_pointer(Token t) {
return nullptr; return nullptr;
} }
return TypeManager::Instance()->Get( return ctx_.type_mgr->Get(
std::make_unique<ast::type::PointerType>(subtype, sc)); std::make_unique<ast::type::PointerType>(subtype, sc));
} }
@ -837,7 +839,7 @@ ast::type::Type* ParserImpl::type_decl_vector(Token t) {
return nullptr; return nullptr;
} }
return TypeManager::Instance()->Get( return ctx_.type_mgr->Get(
std::make_unique<ast::type::VectorType>(subtype, count)); std::make_unique<ast::type::VectorType>(subtype, count));
} }
@ -878,7 +880,7 @@ ast::type::Type* ParserImpl::type_decl_array(Token t) {
return nullptr; return nullptr;
} }
return TypeManager::Instance()->Get( return ctx_.type_mgr->Get(
std::make_unique<ast::type::ArrayType>(subtype, size)); std::make_unique<ast::type::ArrayType>(subtype, size));
} }
@ -918,7 +920,7 @@ ast::type::Type* ParserImpl::type_decl_matrix(Token t) {
return nullptr; return nullptr;
} }
return TypeManager::Instance()->Get( return ctx_.type_mgr->Get(
std::make_unique<ast::type::MatrixType>(subtype, rows, columns)); std::make_unique<ast::type::MatrixType>(subtype, rows, columns));
} }
@ -1209,12 +1211,10 @@ std::unique_ptr<ast::Function> ParserImpl::function_decl() {
// : type_decl // : type_decl
// | VOID // | VOID
ast::type::Type* ParserImpl::function_type_decl() { ast::type::Type* ParserImpl::function_type_decl() {
auto tm = TypeManager::Instance();
auto t = peek(); auto t = peek();
if (t.IsVoid()) { if (t.IsVoid()) {
next(); // Consume the peek next(); // Consume the peek
return tm->Get(std::make_unique<ast::type::VoidType>()); return ctx_.type_mgr->Get(std::make_unique<ast::type::VoidType>());
} }
return type_decl(); return type_decl();
} }

View File

@ -44,6 +44,7 @@
#include "src/ast/unless_statement.h" #include "src/ast/unless_statement.h"
#include "src/ast/variable.h" #include "src/ast/variable.h"
#include "src/ast/variable_decoration.h" #include "src/ast/variable_decoration.h"
#include "src/context.h"
#include "src/reader/wgsl/token.h" #include "src/reader/wgsl/token.h"
namespace tint { namespace tint {
@ -56,8 +57,9 @@ class Lexer;
class ParserImpl { class ParserImpl {
public: public:
/// Creates a new parser /// Creates a new parser
/// @param ctx the context object
/// @param input the input string to parse /// @param input the input string to parse
explicit ParserImpl(const std::string& input); ParserImpl(const Context& ctx, const std::string& input);
~ParserImpl(); ~ParserImpl();
/// Run the parser /// Run the parser
@ -349,6 +351,7 @@ class ParserImpl {
ast::type::Type* type_decl_array(Token t); ast::type::Type* type_decl_array(Token t);
ast::type::Type* type_decl_matrix(Token t); ast::type::Type* type_decl_matrix(Token t);
const Context& ctx_;
std::string error_; std::string error_;
std::unique_ptr<Lexer> lexer_; std::unique_ptr<Lexer> lexer_;
std::deque<Token> token_queue_; std::deque<Token> token_queue_;

View File

@ -18,17 +18,16 @@
#include "src/ast/identifier_expression.h" #include "src/ast/identifier_expression.h"
#include "src/ast/relational_expression.h" #include "src/ast/relational_expression.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, AdditiveExpression_Parses_Plus) { TEST_F(ParserImplTest, AdditiveExpression_Parses_Plus) {
ParserImpl p{"a + true"}; auto p = parser("a + true");
auto e = p.additive_expression(); auto e = p->additive_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRelational()); ASSERT_TRUE(e->IsRelational());
@ -48,9 +47,9 @@ TEST_F(ParserImplTest, AdditiveExpression_Parses_Plus) {
} }
TEST_F(ParserImplTest, AdditiveExpression_Parses_Minus) { TEST_F(ParserImplTest, AdditiveExpression_Parses_Minus) {
ParserImpl p{"a - true"}; auto p = parser("a - true");
auto e = p.additive_expression(); auto e = p->additive_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRelational()); ASSERT_TRUE(e->IsRelational());
@ -70,24 +69,24 @@ TEST_F(ParserImplTest, AdditiveExpression_Parses_Minus) {
} }
TEST_F(ParserImplTest, AdditiveExpression_InvalidLHS) { TEST_F(ParserImplTest, AdditiveExpression_InvalidLHS) {
ParserImpl p{"if (a) {} + true"}; auto p = parser("if (a) {} + true");
auto e = p.additive_expression(); auto e = p->additive_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
} }
TEST_F(ParserImplTest, AdditiveExpression_InvalidRHS) { TEST_F(ParserImplTest, AdditiveExpression_InvalidRHS) {
ParserImpl p{"true + if (a) {}"}; auto p = parser("true + if (a) {}");
auto e = p.additive_expression(); auto e = p->additive_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: unable to parse right side of + expression"); EXPECT_EQ(p->error(), "1:8: unable to parse right side of + expression");
} }
TEST_F(ParserImplTest, AdditiveExpression_NoOr_ReturnsLHS) { TEST_F(ParserImplTest, AdditiveExpression_NoOr_ReturnsLHS) {
ParserImpl p{"a true"}; auto p = parser("a true");
auto e = p.additive_expression(); auto e = p->additive_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsIdentifier()); ASSERT_TRUE(e->IsIdentifier());
} }

View File

@ -18,17 +18,16 @@
#include "src/ast/identifier_expression.h" #include "src/ast/identifier_expression.h"
#include "src/ast/relational_expression.h" #include "src/ast/relational_expression.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, AndExpression_Parses) { TEST_F(ParserImplTest, AndExpression_Parses) {
ParserImpl p{"a & true"}; auto p = parser("a & true");
auto e = p.and_expression(); auto e = p->and_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRelational()); ASSERT_TRUE(e->IsRelational());
@ -48,24 +47,24 @@ TEST_F(ParserImplTest, AndExpression_Parses) {
} }
TEST_F(ParserImplTest, AndExpression_InvalidLHS) { TEST_F(ParserImplTest, AndExpression_InvalidLHS) {
ParserImpl p{"if (a) {} & true"}; auto p = parser("if (a) {} & true");
auto e = p.and_expression(); auto e = p->and_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
} }
TEST_F(ParserImplTest, AndExpression_InvalidRHS) { TEST_F(ParserImplTest, AndExpression_InvalidRHS) {
ParserImpl p{"true & if (a) {}"}; auto p = parser("true & if (a) {}");
auto e = p.and_expression(); auto e = p->and_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: unable to parse right side of & expression"); EXPECT_EQ(p->error(), "1:8: unable to parse right side of & expression");
} }
TEST_F(ParserImplTest, AndExpression_NoOr_ReturnsLHS) { TEST_F(ParserImplTest, AndExpression_NoOr_ReturnsLHS) {
ParserImpl p{"a true"}; auto p = parser("a true");
auto e = p.and_expression(); auto e = p->and_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsIdentifier()); ASSERT_TRUE(e->IsIdentifier());
} }

View File

@ -21,26 +21,25 @@
#include "src/ast/unary_method_expression.h" #include "src/ast/unary_method_expression.h"
#include "src/ast/unary_op_expression.h" #include "src/ast/unary_op_expression.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, ArgumentExpressionList_Parses) { TEST_F(ParserImplTest, ArgumentExpressionList_Parses) {
ParserImpl p{"a"}; auto p = parser("a");
auto e = p.argument_expression_list(); auto e = p->argument_expression_list();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e.size(), 1); ASSERT_EQ(e.size(), 1);
ASSERT_TRUE(e[0]->IsIdentifier()); ASSERT_TRUE(e[0]->IsIdentifier());
} }
TEST_F(ParserImplTest, ArgumentExpressionList_ParsesMultiple) { TEST_F(ParserImplTest, ArgumentExpressionList_ParsesMultiple) {
ParserImpl p{"a, -33, 1+2"}; auto p = parser("a, -33, 1+2");
auto e = p.argument_expression_list(); auto e = p->argument_expression_list();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e.size(), 3); ASSERT_EQ(e.size(), 3);
ASSERT_TRUE(e[0]->IsIdentifier()); ASSERT_TRUE(e[0]->IsIdentifier());
@ -49,17 +48,17 @@ TEST_F(ParserImplTest, ArgumentExpressionList_ParsesMultiple) {
} }
TEST_F(ParserImplTest, ArgumentExpressionList_HandlesMissingExpression) { TEST_F(ParserImplTest, ArgumentExpressionList_HandlesMissingExpression) {
ParserImpl p{"a, "}; auto p = parser("a, ");
auto e = p.argument_expression_list(); auto e = p->argument_expression_list();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:4: unable to parse argument expression after comma"); EXPECT_EQ(p->error(), "1:4: unable to parse argument expression after comma");
} }
TEST_F(ParserImplTest, ArgumentExpressionList_HandlesInvalidExpression) { TEST_F(ParserImplTest, ArgumentExpressionList_HandlesInvalidExpression) {
ParserImpl p{"if(a) {}"}; auto p = parser("if(a) {}");
auto e = p.argument_expression_list(); auto e = p->argument_expression_list();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:1: unable to parse argument expression"); EXPECT_EQ(p->error(), "1:1: unable to parse argument expression");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -21,17 +21,16 @@
#include "src/ast/literal.h" #include "src/ast/literal.h"
#include "src/ast/member_accessor_expression.h" #include "src/ast/member_accessor_expression.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, AssignmentStmt_Parses_ToVariable) { TEST_F(ParserImplTest, AssignmentStmt_Parses_ToVariable) {
ParserImpl p{"a = 123"}; auto p = parser("a = 123");
auto e = p.assignment_stmt(); auto e = p->assignment_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsAssign()); ASSERT_TRUE(e->IsAssign());
@ -53,9 +52,9 @@ TEST_F(ParserImplTest, AssignmentStmt_Parses_ToVariable) {
} }
TEST_F(ParserImplTest, AssignmentStmt_Parses_ToMember) { TEST_F(ParserImplTest, AssignmentStmt_Parses_ToMember) {
ParserImpl p{"a.b.c[2].d = 123"}; auto p = parser("a.b.c[2].d = 123");
auto e = p.assignment_stmt(); auto e = p->assignment_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsAssign()); ASSERT_TRUE(e->IsAssign());
@ -109,26 +108,26 @@ TEST_F(ParserImplTest, AssignmentStmt_Parses_ToMember) {
} }
TEST_F(ParserImplTest, AssignmentStmt_MissingEqual) { TEST_F(ParserImplTest, AssignmentStmt_MissingEqual) {
ParserImpl p{"a.b.c[2].d 123"}; auto p = parser("a.b.c[2].d 123");
auto e = p.assignment_stmt(); auto e = p->assignment_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:12: missing = for assignment"); EXPECT_EQ(p->error(), "1:12: missing = for assignment");
} }
TEST_F(ParserImplTest, AssignmentStmt_InvalidLHS) { TEST_F(ParserImplTest, AssignmentStmt_InvalidLHS) {
ParserImpl p{"if (true) {} = 123"}; auto p = parser("if (true) {} = 123");
auto e = p.assignment_stmt(); auto e = p->assignment_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
} }
TEST_F(ParserImplTest, AssignmentStmt_InvalidRHS) { TEST_F(ParserImplTest, AssignmentStmt_InvalidRHS) {
ParserImpl p{"a.b.c[2].d = if (true) {}"}; auto p = parser("a.b.c[2].d = if (true) {}");
auto e = p.assignment_stmt(); auto e = p->assignment_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:14: unable to parse right side of assignment"); EXPECT_EQ(p->error(), "1:14: unable to parse right side of assignment");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -14,21 +14,20 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, BodyStmt) { TEST_F(ParserImplTest, BodyStmt) {
ParserImpl p{R"({ auto p = parser(R"({
kill; kill;
nop; nop;
return 1 + b / 2; return 1 + b / 2;
})"}; })");
auto e = p.body_stmt(); auto e = p->body_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e.size(), 3); ASSERT_EQ(e.size(), 3);
EXPECT_TRUE(e[0]->IsKill()); EXPECT_TRUE(e[0]->IsKill());
EXPECT_TRUE(e[1]->IsNop()); EXPECT_TRUE(e[1]->IsNop());
@ -36,24 +35,24 @@ TEST_F(ParserImplTest, BodyStmt) {
} }
TEST_F(ParserImplTest, BodyStmt_Empty) { TEST_F(ParserImplTest, BodyStmt_Empty) {
ParserImpl p{"{}"}; auto p = parser("{}");
auto e = p.body_stmt(); auto e = p->body_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_EQ(e.size(), 0); EXPECT_EQ(e.size(), 0);
} }
TEST_F(ParserImplTest, BodyStmt_InvalidStmt) { TEST_F(ParserImplTest, BodyStmt_InvalidStmt) {
ParserImpl p{"{fn main() -> void {}}"}; auto p = parser("{fn main() -> void {}}");
auto e = p.body_stmt(); auto e = p->body_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:2: missing }"); EXPECT_EQ(p->error(), "1:2: missing }");
} }
TEST_F(ParserImplTest, BodyStmt_MissingRightParen) { TEST_F(ParserImplTest, BodyStmt_MissingRightParen) {
ParserImpl p{"{return;"}; auto p = parser("{return;");
auto e = p.body_stmt(); auto e = p->body_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:9: missing }"); EXPECT_EQ(p->error(), "1:9: missing }");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -17,17 +17,16 @@
#include "src/ast/return_statement.h" #include "src/ast/return_statement.h"
#include "src/ast/statement.h" #include "src/ast/statement.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, BreakStmt) { TEST_F(ParserImplTest, BreakStmt) {
ParserImpl p{"break"}; auto p = parser("break");
auto e = p.break_stmt(); auto e = p->break_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsBreak()); ASSERT_TRUE(e->IsBreak());
EXPECT_EQ(e->condition(), ast::StatementCondition::kNone); EXPECT_EQ(e->condition(), ast::StatementCondition::kNone);
@ -35,9 +34,9 @@ TEST_F(ParserImplTest, BreakStmt) {
} }
TEST_F(ParserImplTest, BreakStmt_WithIf) { TEST_F(ParserImplTest, BreakStmt_WithIf) {
ParserImpl p{"break if (a == b)"}; auto p = parser("break if (a == b)");
auto e = p.break_stmt(); auto e = p->break_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsBreak()); ASSERT_TRUE(e->IsBreak());
EXPECT_EQ(e->condition(), ast::StatementCondition::kIf); EXPECT_EQ(e->condition(), ast::StatementCondition::kIf);
@ -46,9 +45,9 @@ TEST_F(ParserImplTest, BreakStmt_WithIf) {
} }
TEST_F(ParserImplTest, BreakStmt_WithUnless) { TEST_F(ParserImplTest, BreakStmt_WithUnless) {
ParserImpl p{"break unless (a == b)"}; auto p = parser("break unless (a == b)");
auto e = p.break_stmt(); auto e = p->break_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsBreak()); ASSERT_TRUE(e->IsBreak());
EXPECT_EQ(e->condition(), ast::StatementCondition::kUnless); EXPECT_EQ(e->condition(), ast::StatementCondition::kUnless);
@ -57,19 +56,19 @@ TEST_F(ParserImplTest, BreakStmt_WithUnless) {
} }
TEST_F(ParserImplTest, BreakStmt_InvalidRHS) { TEST_F(ParserImplTest, BreakStmt_InvalidRHS) {
ParserImpl p{"break if (a = b)"}; auto p = parser("break if (a = b)");
auto e = p.break_stmt(); auto e = p->break_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:13: expected )"); EXPECT_EQ(p->error(), "1:13: expected )");
} }
TEST_F(ParserImplTest, BreakStmt_MissingRHS) { TEST_F(ParserImplTest, BreakStmt_MissingRHS) {
ParserImpl p{"break if"}; auto p = parser("break if");
auto e = p.break_stmt(); auto e = p->break_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:9: expected ("); EXPECT_EQ(p->error(), "1:9: expected (");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -15,12 +15,12 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/ast/builtin.h" #include "src/ast/builtin.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
namespace {
using ParserImplTest = testing::Test;
struct BuiltinData { struct BuiltinData {
const char* input; const char* input;
@ -30,16 +30,41 @@ inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
out << std::string(data.input); out << std::string(data.input);
return out; return out;
} }
using BuiltinTest = testing::TestWithParam<BuiltinData>;
class BuiltinTest : public testing::TestWithParam<BuiltinData> {
public:
BuiltinTest() = default;
~BuiltinTest() = default;
void SetUp() { ctx_.type_mgr = &tm_; }
void TearDown() {
impl_ = nullptr;
ctx_.type_mgr = nullptr;
}
ParserImpl* parser(const std::string& str) {
impl_ = std::make_unique<ParserImpl>(ctx_, str);
return impl_.get();
}
private:
std::unique_ptr<ParserImpl> impl_;
Context ctx_;
TypeManager tm_;
};
} // namespace
TEST_P(BuiltinTest, Parses) { TEST_P(BuiltinTest, Parses) {
auto params = GetParam(); auto params = GetParam();
ParserImpl p{params.input}; auto p = parser(params.input);
auto builtin = p.builtin_decoration(); auto builtin = p->builtin_decoration();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
EXPECT_EQ(builtin, params.result); EXPECT_EQ(builtin, params.result);
auto t = p.next(); auto t = p->next();
EXPECT_TRUE(t.IsEof()); EXPECT_TRUE(t.IsEof());
} }
INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P(
@ -60,11 +85,11 @@ INSTANTIATE_TEST_SUITE_P(
ast::Builtin::kGlobalInvocationId})); ast::Builtin::kGlobalInvocationId}));
TEST_F(ParserImplTest, BuiltinDecoration_NoMatch) { TEST_F(ParserImplTest, BuiltinDecoration_NoMatch) {
ParserImpl p{"not-a-builtin"}; auto p = parser("not-a-builtin");
auto builtin = p.builtin_decoration(); auto builtin = p->builtin_decoration();
ASSERT_EQ(builtin, ast::Builtin::kNone); ASSERT_EQ(builtin, ast::Builtin::kNone);
auto t = p.next(); auto t = p->next();
EXPECT_TRUE(t.IsIdentifier()); EXPECT_TRUE(t.IsIdentifier());
EXPECT_EQ(t.to_str(), "not"); EXPECT_EQ(t.to_str(), "not");
} }

View File

@ -14,54 +14,53 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, CaseBody_Empty) { TEST_F(ParserImplTest, CaseBody_Empty) {
ParserImpl p{""}; auto p = parser("");
auto e = p.case_body(); auto e = p->case_body();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_EQ(e.size(), 0); EXPECT_EQ(e.size(), 0);
} }
TEST_F(ParserImplTest, CaseBody_Statements) { TEST_F(ParserImplTest, CaseBody_Statements) {
ParserImpl p{R"( auto p = parser(R"(
var a: i32; var a: i32;
a = 2;)"}; a = 2;)");
auto e = p.case_body(); auto e = p->case_body();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e.size(), 2); ASSERT_EQ(e.size(), 2);
EXPECT_TRUE(e[0]->IsVariable()); EXPECT_TRUE(e[0]->IsVariable());
EXPECT_TRUE(e[1]->IsAssign()); EXPECT_TRUE(e[1]->IsAssign());
} }
TEST_F(ParserImplTest, CaseBody_InvalidStatement) { TEST_F(ParserImplTest, CaseBody_InvalidStatement) {
ParserImpl p{"a ="}; auto p = parser("a =");
auto e = p.case_body(); auto e = p->case_body();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(e.size(), 0); EXPECT_EQ(e.size(), 0);
EXPECT_EQ(p.error(), "1:4: unable to parse right side of assignment"); EXPECT_EQ(p->error(), "1:4: unable to parse right side of assignment");
} }
TEST_F(ParserImplTest, CaseBody_Fallthrough) { TEST_F(ParserImplTest, CaseBody_Fallthrough) {
ParserImpl p{"fallthrough;"}; auto p = parser("fallthrough;");
auto e = p.case_body(); auto e = p->case_body();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e.size(), 1); ASSERT_EQ(e.size(), 1);
EXPECT_TRUE(e[0]->IsFallthrough()); EXPECT_TRUE(e[0]->IsFallthrough());
} }
TEST_F(ParserImplTest, CaseBody_Fallthrough_MissingSemicolon) { TEST_F(ParserImplTest, CaseBody_Fallthrough_MissingSemicolon) {
ParserImpl p{"fallthrough"}; auto p = parser("fallthrough");
auto e = p.case_body(); auto e = p->case_body();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(e.size(), 0); EXPECT_EQ(e.size(), 0);
EXPECT_EQ(p.error(), "1:12: missing ;"); EXPECT_EQ(p->error(), "1:12: missing ;");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -19,17 +19,16 @@
#include "src/ast/type/vector_type.h" #include "src/ast/type/vector_type.h"
#include "src/ast/type_initializer_expression.h" #include "src/ast/type_initializer_expression.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, ConstExpr_TypeDecl) { TEST_F(ParserImplTest, ConstExpr_TypeDecl) {
ParserImpl p{"vec2<f32>(1., 2.)"}; auto p = parser("vec2<f32>(1., 2.)");
auto e = p.const_expr(); auto e = p->const_expr();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsInitializer()); ASSERT_TRUE(e->IsInitializer());
ASSERT_TRUE(e->AsInitializer()->IsTypeInitializer()); ASSERT_TRUE(e->AsInitializer()->IsTypeInitializer());
@ -55,57 +54,57 @@ TEST_F(ParserImplTest, ConstExpr_TypeDecl) {
} }
TEST_F(ParserImplTest, ConstExpr_TypeDecl_MissingRightParen) { TEST_F(ParserImplTest, ConstExpr_TypeDecl_MissingRightParen) {
ParserImpl p{"vec2<f32>(1., 2."}; auto p = parser("vec2<f32>(1., 2.");
auto e = p.const_expr(); auto e = p->const_expr();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:17: missing ) for type initializer"); EXPECT_EQ(p->error(), "1:17: missing ) for type initializer");
} }
TEST_F(ParserImplTest, ConstExpr_TypeDecl_MissingLeftParen) { TEST_F(ParserImplTest, ConstExpr_TypeDecl_MissingLeftParen) {
ParserImpl p{"vec2<f32> 1., 2.)"}; auto p = parser("vec2<f32> 1., 2.)");
auto e = p.const_expr(); auto e = p->const_expr();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:11: missing ( for type initializer"); EXPECT_EQ(p->error(), "1:11: missing ( for type initializer");
} }
TEST_F(ParserImplTest, ConstExpr_TypeDecl_HangingComma) { TEST_F(ParserImplTest, ConstExpr_TypeDecl_HangingComma) {
ParserImpl p{"vec2<f32>(1.,)"}; auto p = parser("vec2<f32>(1.,)");
auto e = p.const_expr(); auto e = p->const_expr();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:14: unable to parse const literal"); EXPECT_EQ(p->error(), "1:14: unable to parse const literal");
} }
TEST_F(ParserImplTest, ConstExpr_TypeDecl_MissingComma) { TEST_F(ParserImplTest, ConstExpr_TypeDecl_MissingComma) {
ParserImpl p{"vec2<f32>(1. 2."}; auto p = parser("vec2<f32>(1. 2.");
auto e = p.const_expr(); auto e = p->const_expr();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:14: missing ) for type initializer"); EXPECT_EQ(p->error(), "1:14: missing ) for type initializer");
} }
TEST_F(ParserImplTest, ConstExpr_MissingExpr) { TEST_F(ParserImplTest, ConstExpr_MissingExpr) {
ParserImpl p{"vec2<f32>()"}; auto p = parser("vec2<f32>()");
auto e = p.const_expr(); auto e = p->const_expr();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:11: unable to parse const literal"); EXPECT_EQ(p->error(), "1:11: unable to parse const literal");
} }
TEST_F(ParserImplTest, ConstExpr_InvalidExpr) { TEST_F(ParserImplTest, ConstExpr_InvalidExpr) {
ParserImpl p{"vec2<f32>(1., if(a) {})"}; auto p = parser("vec2<f32>(1., if(a) {})");
auto e = p.const_expr(); auto e = p->const_expr();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:15: unable to parse const literal"); EXPECT_EQ(p->error(), "1:15: unable to parse const literal");
} }
TEST_F(ParserImplTest, ConstExpr_ConstLiteral) { TEST_F(ParserImplTest, ConstExpr_ConstLiteral) {
ParserImpl p{"true"}; auto p = parser("true");
auto e = p.const_expr(); auto e = p->const_expr();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsInitializer()); ASSERT_TRUE(e->IsInitializer());
ASSERT_TRUE(e->AsInitializer()->IsConstInitializer()); ASSERT_TRUE(e->AsInitializer()->IsConstInitializer());
@ -115,11 +114,11 @@ TEST_F(ParserImplTest, ConstExpr_ConstLiteral) {
} }
TEST_F(ParserImplTest, ConstExpr_ConstLiteral_Invalid) { TEST_F(ParserImplTest, ConstExpr_ConstLiteral_Invalid) {
ParserImpl p{"invalid"}; auto p = parser("invalid");
auto e = p.const_expr(); auto e = p->const_expr();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:1: unknown type alias 'invalid'"); EXPECT_EQ(p->error(), "1:1: unknown type alias 'invalid'");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -18,68 +18,67 @@
#include "src/ast/int_literal.h" #include "src/ast/int_literal.h"
#include "src/ast/uint_literal.h" #include "src/ast/uint_literal.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, ConstLiteral_Int) { TEST_F(ParserImplTest, ConstLiteral_Int) {
ParserImpl p{"-234"}; auto p = parser("-234");
auto c = p.const_literal(); auto c = p->const_literal();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_NE(c, nullptr); ASSERT_NE(c, nullptr);
ASSERT_TRUE(c->IsInt()); ASSERT_TRUE(c->IsInt());
EXPECT_EQ(c->AsInt()->value(), -234); EXPECT_EQ(c->AsInt()->value(), -234);
} }
TEST_F(ParserImplTest, ConstLiteral_Uint) { TEST_F(ParserImplTest, ConstLiteral_Uint) {
ParserImpl p{"234u"}; auto p = parser("234u");
auto c = p.const_literal(); auto c = p->const_literal();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_NE(c, nullptr); ASSERT_NE(c, nullptr);
ASSERT_TRUE(c->IsUint()); ASSERT_TRUE(c->IsUint());
EXPECT_EQ(c->AsUint()->value(), 234u); EXPECT_EQ(c->AsUint()->value(), 234u);
} }
TEST_F(ParserImplTest, ConstLiteral_Float) { TEST_F(ParserImplTest, ConstLiteral_Float) {
ParserImpl p{"234.e12"}; auto p = parser("234.e12");
auto c = p.const_literal(); auto c = p->const_literal();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_NE(c, nullptr); ASSERT_NE(c, nullptr);
ASSERT_TRUE(c->IsFloat()); ASSERT_TRUE(c->IsFloat());
EXPECT_FLOAT_EQ(c->AsFloat()->value(), 234e12); EXPECT_FLOAT_EQ(c->AsFloat()->value(), 234e12);
} }
TEST_F(ParserImplTest, ConstLiteral_InvalidFloat) { TEST_F(ParserImplTest, ConstLiteral_InvalidFloat) {
ParserImpl p{"1.2e+256"}; auto p = parser("1.2e+256");
auto c = p.const_literal(); auto c = p->const_literal();
ASSERT_EQ(c, nullptr); ASSERT_EQ(c, nullptr);
} }
TEST_F(ParserImplTest, ConstLiteral_True) { TEST_F(ParserImplTest, ConstLiteral_True) {
ParserImpl p{"true"}; auto p = parser("true");
auto c = p.const_literal(); auto c = p->const_literal();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_NE(c, nullptr); ASSERT_NE(c, nullptr);
ASSERT_TRUE(c->IsBool()); ASSERT_TRUE(c->IsBool());
EXPECT_TRUE(c->AsBool()->IsTrue()); EXPECT_TRUE(c->AsBool()->IsTrue());
} }
TEST_F(ParserImplTest, ConstLiteral_False) { TEST_F(ParserImplTest, ConstLiteral_False) {
ParserImpl p{"false"}; auto p = parser("false");
auto c = p.const_literal(); auto c = p->const_literal();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_NE(c, nullptr); ASSERT_NE(c, nullptr);
ASSERT_TRUE(c->IsBool()); ASSERT_TRUE(c->IsBool());
EXPECT_TRUE(c->AsBool()->IsFalse()); EXPECT_TRUE(c->AsBool()->IsFalse());
} }
TEST_F(ParserImplTest, ConstLiteral_NoMatch) { TEST_F(ParserImplTest, ConstLiteral_NoMatch) {
ParserImpl p{"another-token"}; auto p = parser("another-token");
auto c = p.const_literal(); auto c = p->const_literal();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_EQ(c, nullptr); ASSERT_EQ(c, nullptr);
} }

View File

@ -17,17 +17,16 @@
#include "src/ast/return_statement.h" #include "src/ast/return_statement.h"
#include "src/ast/statement.h" #include "src/ast/statement.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, ContinueStmt) { TEST_F(ParserImplTest, ContinueStmt) {
ParserImpl p{"continue"}; auto p = parser("continue");
auto e = p.continue_stmt(); auto e = p->continue_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsContinue()); ASSERT_TRUE(e->IsContinue());
EXPECT_EQ(e->condition(), ast::StatementCondition::kNone); EXPECT_EQ(e->condition(), ast::StatementCondition::kNone);
@ -35,9 +34,9 @@ TEST_F(ParserImplTest, ContinueStmt) {
} }
TEST_F(ParserImplTest, ContinueStmt_WithIf) { TEST_F(ParserImplTest, ContinueStmt_WithIf) {
ParserImpl p{"continue if (a == b)"}; auto p = parser("continue if (a == b)");
auto e = p.continue_stmt(); auto e = p->continue_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsContinue()); ASSERT_TRUE(e->IsContinue());
EXPECT_EQ(e->condition(), ast::StatementCondition::kIf); EXPECT_EQ(e->condition(), ast::StatementCondition::kIf);
@ -46,9 +45,9 @@ TEST_F(ParserImplTest, ContinueStmt_WithIf) {
} }
TEST_F(ParserImplTest, ContinueStmt_WithUnless) { TEST_F(ParserImplTest, ContinueStmt_WithUnless) {
ParserImpl p{"continue unless (a == b)"}; auto p = parser("continue unless (a == b)");
auto e = p.continue_stmt(); auto e = p->continue_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsContinue()); ASSERT_TRUE(e->IsContinue());
EXPECT_EQ(e->condition(), ast::StatementCondition::kUnless); EXPECT_EQ(e->condition(), ast::StatementCondition::kUnless);
@ -57,19 +56,19 @@ TEST_F(ParserImplTest, ContinueStmt_WithUnless) {
} }
TEST_F(ParserImplTest, ContinueStmt_InvalidRHS) { TEST_F(ParserImplTest, ContinueStmt_InvalidRHS) {
ParserImpl p{"continue if (a = b)"}; auto p = parser("continue if (a = b)");
auto e = p.continue_stmt(); auto e = p->continue_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:16: expected )"); EXPECT_EQ(p->error(), "1:16: expected )");
} }
TEST_F(ParserImplTest, ContinueStmt_MissingRHS) { TEST_F(ParserImplTest, ContinueStmt_MissingRHS) {
ParserImpl p{"continue if"}; auto p = parser("continue if");
auto e = p.continue_stmt(); auto e = p->continue_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:12: expected ("); EXPECT_EQ(p->error(), "1:12: expected (");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -14,27 +14,26 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, ContinuingStmt) { TEST_F(ParserImplTest, ContinuingStmt) {
ParserImpl p{"continuing { nop; }"}; auto p = parser("continuing { nop; }");
auto e = p.continuing_stmt(); auto e = p->continuing_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e.size(), 1); ASSERT_EQ(e.size(), 1);
ASSERT_TRUE(e[0]->IsNop()); ASSERT_TRUE(e[0]->IsNop());
} }
TEST_F(ParserImplTest, ContinuingStmt_InvalidBody) { TEST_F(ParserImplTest, ContinuingStmt_InvalidBody) {
ParserImpl p{"continuing { nop }"}; auto p = parser("continuing { nop }");
auto e = p.continuing_stmt(); auto e = p->continuing_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e.size(), 0); ASSERT_EQ(e.size(), 0);
EXPECT_EQ(p.error(), "1:18: missing ;"); EXPECT_EQ(p->error(), "1:18: missing ;");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -15,12 +15,12 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/ast/derivative_modifier.h" #include "src/ast/derivative_modifier.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
namespace {
using ParserImplTest = testing::Test;
struct DerivativeModifierData { struct DerivativeModifierData {
const char* input; const char* input;
@ -31,16 +31,42 @@ inline std::ostream& operator<<(std::ostream& out,
out << std::string(data.input); out << std::string(data.input);
return out; return out;
} }
using DerivativeModifierTest = testing::TestWithParam<DerivativeModifierData>;
class DerivativeModifierTest
: public testing::TestWithParam<DerivativeModifierData> {
public:
DerivativeModifierTest() = default;
~DerivativeModifierTest() = default;
void SetUp() { ctx_.type_mgr = &tm_; }
void TearDown() {
impl_ = nullptr;
ctx_.type_mgr = nullptr;
}
ParserImpl* parser(const std::string& str) {
impl_ = std::make_unique<ParserImpl>(ctx_, str);
return impl_.get();
}
private:
std::unique_ptr<ParserImpl> impl_;
Context ctx_;
TypeManager tm_;
};
} // namespace
TEST_P(DerivativeModifierTest, Parses) { TEST_P(DerivativeModifierTest, Parses) {
auto params = GetParam(); auto params = GetParam();
ParserImpl p{params.input}; auto p = parser(params.input);
auto mod = p.derivative_modifier(); auto mod = p->derivative_modifier();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
EXPECT_EQ(mod, params.result); EXPECT_EQ(mod, params.result);
auto t = p.next(); auto t = p->next();
EXPECT_TRUE(t.IsEof()); EXPECT_TRUE(t.IsEof());
} }
INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P(
@ -51,11 +77,11 @@ INSTANTIATE_TEST_SUITE_P(
DerivativeModifierData{"coarse", ast::DerivativeModifier::kCoarse})); DerivativeModifierData{"coarse", ast::DerivativeModifier::kCoarse}));
TEST_F(ParserImplTest, DerivativeModifier_NoMatch) { TEST_F(ParserImplTest, DerivativeModifier_NoMatch) {
ParserImpl p{"not-a-modifier"}; auto p = parser("not-a-modifier");
auto stage = p.derivative_modifier(); auto stage = p->derivative_modifier();
ASSERT_EQ(stage, ast::DerivativeModifier::kNone); ASSERT_EQ(stage, ast::DerivativeModifier::kNone);
auto t = p.next(); auto t = p->next();
EXPECT_TRUE(t.IsIdentifier()); EXPECT_TRUE(t.IsIdentifier());
EXPECT_EQ(t.to_str(), "not"); EXPECT_EQ(t.to_str(), "not");
} }

View File

@ -15,17 +15,16 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/ast/else_statement.h" #include "src/ast/else_statement.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, ElseStmt) { TEST_F(ParserImplTest, ElseStmt) {
ParserImpl p{"else { a = b; c = d; }"}; auto p = parser("else { a = b; c = d; }");
auto e = p.else_stmt(); auto e = p->else_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsElse()); ASSERT_TRUE(e->IsElse());
ASSERT_EQ(e->condition(), nullptr); ASSERT_EQ(e->condition(), nullptr);
@ -33,19 +32,19 @@ TEST_F(ParserImplTest, ElseStmt) {
} }
TEST_F(ParserImplTest, ElseStmt_InvalidBody) { TEST_F(ParserImplTest, ElseStmt_InvalidBody) {
ParserImpl p{"else { fn main() -> void {}}"}; auto p = parser("else { fn main() -> void {}}");
auto e = p.else_stmt(); auto e = p->else_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: missing }"); EXPECT_EQ(p->error(), "1:8: missing }");
} }
TEST_F(ParserImplTest, ElseStmt_MissingBody) { TEST_F(ParserImplTest, ElseStmt_MissingBody) {
ParserImpl p{"else"}; auto p = parser("else");
auto e = p.else_stmt(); auto e = p->else_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:5: missing {"); EXPECT_EQ(p->error(), "1:5: missing {");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -15,17 +15,16 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/ast/else_statement.h" #include "src/ast/else_statement.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, ElseIfStmt) { TEST_F(ParserImplTest, ElseIfStmt) {
ParserImpl p{"elseif (a == 4) { a = b; c = d; }"}; auto p = parser("elseif (a == 4) { a = b; c = d; }");
auto e = p.elseif_stmt(); auto e = p->elseif_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e.size(), 1); ASSERT_EQ(e.size(), 1);
ASSERT_TRUE(e[0]->IsElse()); ASSERT_TRUE(e[0]->IsElse());
@ -35,9 +34,9 @@ TEST_F(ParserImplTest, ElseIfStmt) {
} }
TEST_F(ParserImplTest, ElseIfStmt_Multiple) { TEST_F(ParserImplTest, ElseIfStmt_Multiple) {
ParserImpl p{"elseif (a == 4) { a = b; c = d; } elseif(c) { d = 2; }"}; auto p = parser("elseif (a == 4) { a = b; c = d; } elseif(c) { d = 2; }");
auto e = p.elseif_stmt(); auto e = p->elseif_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e.size(), 2); ASSERT_EQ(e.size(), 2);
ASSERT_TRUE(e[0]->IsElse()); ASSERT_TRUE(e[0]->IsElse());
@ -52,17 +51,17 @@ TEST_F(ParserImplTest, ElseIfStmt_Multiple) {
} }
TEST_F(ParserImplTest, ElseIfStmt_InvalidBody) { TEST_F(ParserImplTest, ElseIfStmt_InvalidBody) {
ParserImpl p{"elseif (true) { fn main() -> void {}}"}; auto p = parser("elseif (true) { fn main() -> void {}}");
auto e = p.elseif_stmt(); auto e = p->elseif_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:17: missing }"); EXPECT_EQ(p->error(), "1:17: missing }");
} }
TEST_F(ParserImplTest, ElseIfStmt_MissingBody) { TEST_F(ParserImplTest, ElseIfStmt_MissingBody) {
ParserImpl p{"elseif (true)"}; auto p = parser("elseif (true)");
auto e = p.elseif_stmt(); auto e = p->elseif_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:14: missing {"); EXPECT_EQ(p->error(), "1:14: missing {");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -15,105 +15,104 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/ast/variable.h" #include "src/ast/variable.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, EntryPoint_Parses) { TEST_F(ParserImplTest, EntryPoint_Parses) {
ParserImpl p{"entry_point fragment = main"}; auto p = parser("entry_point fragment = main");
auto e = p.entry_point_decl(); auto e = p->entry_point_decl();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
EXPECT_EQ(e->stage(), ast::PipelineStage::kFragment); EXPECT_EQ(e->stage(), ast::PipelineStage::kFragment);
EXPECT_EQ(e->name(), "main"); EXPECT_EQ(e->name(), "main");
EXPECT_EQ(e->function_name(), "main"); EXPECT_EQ(e->function_name(), "main");
} }
TEST_F(ParserImplTest, EntryPoint_ParsesWithStringName) { TEST_F(ParserImplTest, EntryPoint_ParsesWithStringName) {
ParserImpl p{R"(entry_point vertex as "main" = vtx_main)"}; auto p = parser(R"(entry_point vertex as "main" = vtx_main)");
auto e = p.entry_point_decl(); auto e = p->entry_point_decl();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
EXPECT_EQ(e->stage(), ast::PipelineStage::kVertex); EXPECT_EQ(e->stage(), ast::PipelineStage::kVertex);
EXPECT_EQ(e->name(), "main"); EXPECT_EQ(e->name(), "main");
EXPECT_EQ(e->function_name(), "vtx_main"); EXPECT_EQ(e->function_name(), "vtx_main");
} }
TEST_F(ParserImplTest, EntryPoint_ParsesWithIdentName) { TEST_F(ParserImplTest, EntryPoint_ParsesWithIdentName) {
ParserImpl p{R"(entry_point vertex as main = vtx_main)"}; auto p = parser(R"(entry_point vertex as main = vtx_main)");
auto e = p.entry_point_decl(); auto e = p->entry_point_decl();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
EXPECT_EQ(e->stage(), ast::PipelineStage::kVertex); EXPECT_EQ(e->stage(), ast::PipelineStage::kVertex);
EXPECT_EQ(e->name(), "main"); EXPECT_EQ(e->name(), "main");
EXPECT_EQ(e->function_name(), "vtx_main"); EXPECT_EQ(e->function_name(), "vtx_main");
} }
TEST_F(ParserImplTest, EntryPoint_MissingFnName) { TEST_F(ParserImplTest, EntryPoint_MissingFnName) {
ParserImpl p{R"(entry_point vertex as main =)"}; auto p = parser(R"(entry_point vertex as main =)");
auto e = p.entry_point_decl(); auto e = p->entry_point_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:29: invalid function name for entry point"); EXPECT_EQ(p->error(), "1:29: invalid function name for entry point");
} }
TEST_F(ParserImplTest, EntryPoint_InvalidFnName) { TEST_F(ParserImplTest, EntryPoint_InvalidFnName) {
ParserImpl p{R"(entry_point vertex as main = 123)"}; auto p = parser(R"(entry_point vertex as main = 123)");
auto e = p.entry_point_decl(); auto e = p->entry_point_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:30: invalid function name for entry point"); EXPECT_EQ(p->error(), "1:30: invalid function name for entry point");
} }
TEST_F(ParserImplTest, EntryPoint_MissingEqual) { TEST_F(ParserImplTest, EntryPoint_MissingEqual) {
ParserImpl p{R"(entry_point vertex as main vtx_main)"}; auto p = parser(R"(entry_point vertex as main vtx_main)");
auto e = p.entry_point_decl(); auto e = p->entry_point_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:28: missing = for entry point"); EXPECT_EQ(p->error(), "1:28: missing = for entry point");
} }
TEST_F(ParserImplTest, EntryPoint_MissingName) { TEST_F(ParserImplTest, EntryPoint_MissingName) {
ParserImpl p{R"(entry_point vertex as = vtx_main)"}; auto p = parser(R"(entry_point vertex as = vtx_main)");
auto e = p.entry_point_decl(); auto e = p->entry_point_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:23: invalid name for entry point"); EXPECT_EQ(p->error(), "1:23: invalid name for entry point");
} }
TEST_F(ParserImplTest, EntryPoint_InvalidName) { TEST_F(ParserImplTest, EntryPoint_InvalidName) {
ParserImpl p{R"(entry_point vertex as 123 = vtx_main)"}; auto p = parser(R"(entry_point vertex as 123 = vtx_main)");
auto e = p.entry_point_decl(); auto e = p->entry_point_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:23: invalid name for entry point"); EXPECT_EQ(p->error(), "1:23: invalid name for entry point");
} }
TEST_F(ParserImplTest, EntryPoint_MissingStageWithIdent) { TEST_F(ParserImplTest, EntryPoint_MissingStageWithIdent) {
ParserImpl p{R"(entry_point as 123 = vtx_main)"}; auto p = parser(R"(entry_point as 123 = vtx_main)");
auto e = p.entry_point_decl(); auto e = p->entry_point_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:13: missing pipeline stage for entry point"); EXPECT_EQ(p->error(), "1:13: missing pipeline stage for entry point");
} }
TEST_F(ParserImplTest, EntryPoint_MissingStage) { TEST_F(ParserImplTest, EntryPoint_MissingStage) {
ParserImpl p{R"(entry_point = vtx_main)"}; auto p = parser(R"(entry_point = vtx_main)");
auto e = p.entry_point_decl(); auto e = p->entry_point_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:13: missing pipeline stage for entry point"); EXPECT_EQ(p->error(), "1:13: missing pipeline stage for entry point");
} }
TEST_F(ParserImplTest, EntryPoint_InvalidStage) { TEST_F(ParserImplTest, EntryPoint_InvalidStage) {
ParserImpl p{R"(entry_point invalid = vtx_main)"}; auto p = parser(R"(entry_point invalid = vtx_main)");
auto e = p.entry_point_decl(); auto e = p->entry_point_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:13: missing pipeline stage for entry point"); EXPECT_EQ(p->error(), "1:13: missing pipeline stage for entry point");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -18,17 +18,16 @@
#include "src/ast/identifier_expression.h" #include "src/ast/identifier_expression.h"
#include "src/ast/relational_expression.h" #include "src/ast/relational_expression.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, EqualityExpression_Parses_Equal) { TEST_F(ParserImplTest, EqualityExpression_Parses_Equal) {
ParserImpl p{"a == true"}; auto p = parser("a == true");
auto e = p.equality_expression(); auto e = p->equality_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRelational()); ASSERT_TRUE(e->IsRelational());
@ -48,9 +47,9 @@ TEST_F(ParserImplTest, EqualityExpression_Parses_Equal) {
} }
TEST_F(ParserImplTest, EqualityExpression_Parses_NotEqual) { TEST_F(ParserImplTest, EqualityExpression_Parses_NotEqual) {
ParserImpl p{"a != true"}; auto p = parser("a != true");
auto e = p.equality_expression(); auto e = p->equality_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRelational()); ASSERT_TRUE(e->IsRelational());
@ -70,24 +69,24 @@ TEST_F(ParserImplTest, EqualityExpression_Parses_NotEqual) {
} }
TEST_F(ParserImplTest, EqualityExpression_InvalidLHS) { TEST_F(ParserImplTest, EqualityExpression_InvalidLHS) {
ParserImpl p{"if (a) {} == true"}; auto p = parser("if (a) {} == true");
auto e = p.equality_expression(); auto e = p->equality_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
} }
TEST_F(ParserImplTest, EqualityExpression_InvalidRHS) { TEST_F(ParserImplTest, EqualityExpression_InvalidRHS) {
ParserImpl p{"true == if (a) {}"}; auto p = parser("true == if (a) {}");
auto e = p.equality_expression(); auto e = p->equality_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:9: unable to parse right side of == expression"); EXPECT_EQ(p->error(), "1:9: unable to parse right side of == expression");
} }
TEST_F(ParserImplTest, EqualityExpression_NoOr_ReturnsLHS) { TEST_F(ParserImplTest, EqualityExpression_NoOr_ReturnsLHS) {
ParserImpl p{"a true"}; auto p = parser("a true");
auto e = p.equality_expression(); auto e = p->equality_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsIdentifier()); ASSERT_TRUE(e->IsIdentifier());
} }

View File

@ -18,17 +18,16 @@
#include "src/ast/identifier_expression.h" #include "src/ast/identifier_expression.h"
#include "src/ast/relational_expression.h" #include "src/ast/relational_expression.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, ExclusiveOrExpression_Parses) { TEST_F(ParserImplTest, ExclusiveOrExpression_Parses) {
ParserImpl p{"a ^ true"}; auto p = parser("a ^ true");
auto e = p.exclusive_or_expression(); auto e = p->exclusive_or_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRelational()); ASSERT_TRUE(e->IsRelational());
@ -48,24 +47,24 @@ TEST_F(ParserImplTest, ExclusiveOrExpression_Parses) {
} }
TEST_F(ParserImplTest, ExclusiveOrExpression_InvalidLHS) { TEST_F(ParserImplTest, ExclusiveOrExpression_InvalidLHS) {
ParserImpl p{"if (a) {} ^ true"}; auto p = parser("if (a) {} ^ true");
auto e = p.exclusive_or_expression(); auto e = p->exclusive_or_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
} }
TEST_F(ParserImplTest, ExclusiveOrExpression_InvalidRHS) { TEST_F(ParserImplTest, ExclusiveOrExpression_InvalidRHS) {
ParserImpl p{"true ^ if (a) {}"}; auto p = parser("true ^ if (a) {}");
auto e = p.exclusive_or_expression(); auto e = p->exclusive_or_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: unable to parse right side of ^ expression"); EXPECT_EQ(p->error(), "1:8: unable to parse right side of ^ expression");
} }
TEST_F(ParserImplTest, ExclusiveOrExpression_NoOr_ReturnsLHS) { TEST_F(ParserImplTest, ExclusiveOrExpression_NoOr_ReturnsLHS) {
ParserImpl p{"a true"}; auto p = parser("a true");
auto e = p.exclusive_or_expression(); auto e = p->exclusive_or_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsIdentifier()); ASSERT_TRUE(e->IsIdentifier());
} }

View File

@ -16,17 +16,16 @@
#include "src/ast/function.h" #include "src/ast/function.h"
#include "src/ast/type/type.h" #include "src/ast/type/type.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, FunctionDecl) { TEST_F(ParserImplTest, FunctionDecl) {
ParserImpl p{"fn main(a : i32, b : f32) -> void { return; }"}; auto p = parser("fn main(a : i32, b : f32) -> void { return; }");
auto f = p.function_decl(); auto f = p->function_decl();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(f, nullptr); ASSERT_NE(f, nullptr);
EXPECT_EQ(f->name(), "main"); EXPECT_EQ(f->name(), "main");
@ -45,19 +44,19 @@ TEST_F(ParserImplTest, FunctionDecl) {
} }
TEST_F(ParserImplTest, FunctionDecl_InvalidHeader) { TEST_F(ParserImplTest, FunctionDecl_InvalidHeader) {
ParserImpl p{"fn main() -> { }"}; auto p = parser("fn main() -> { }");
auto f = p.function_decl(); auto f = p->function_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(f, nullptr); ASSERT_EQ(f, nullptr);
EXPECT_EQ(p.error(), "1:14: unable to determine function return type"); EXPECT_EQ(p->error(), "1:14: unable to determine function return type");
} }
TEST_F(ParserImplTest, FunctionDecl_InvalidBody) { TEST_F(ParserImplTest, FunctionDecl_InvalidBody) {
ParserImpl p{"fn main() -> void { return }"}; auto p = parser("fn main() -> void { return }");
auto f = p.function_decl(); auto f = p->function_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(f, nullptr); ASSERT_EQ(f, nullptr);
EXPECT_EQ(p.error(), "1:28: missing ;"); EXPECT_EQ(p->error(), "1:28: missing ;");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -16,17 +16,16 @@
#include "src/ast/function.h" #include "src/ast/function.h"
#include "src/ast/type/type.h" #include "src/ast/type/type.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, FunctionHeader) { TEST_F(ParserImplTest, FunctionHeader) {
ParserImpl p{"fn main(a : i32, b: f32) -> void"}; auto p = parser("fn main(a : i32, b: f32) -> void");
auto f = p.function_header(); auto f = p->function_header();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(f, nullptr); ASSERT_NE(f, nullptr);
EXPECT_EQ(f->name(), "main"); EXPECT_EQ(f->name(), "main");
@ -37,67 +36,67 @@ TEST_F(ParserImplTest, FunctionHeader) {
} }
TEST_F(ParserImplTest, FunctionHeader_MissingIdent) { TEST_F(ParserImplTest, FunctionHeader_MissingIdent) {
ParserImpl p{"fn () ->"}; auto p = parser("fn () ->");
auto f = p.function_header(); auto f = p->function_header();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(f, nullptr); ASSERT_EQ(f, nullptr);
EXPECT_EQ(p.error(), "1:4: missing identifier for function"); EXPECT_EQ(p->error(), "1:4: missing identifier for function");
} }
TEST_F(ParserImplTest, FunctionHeader_InvalidIdent) { TEST_F(ParserImplTest, FunctionHeader_InvalidIdent) {
ParserImpl p{"fn 133main() -> i32"}; auto p = parser("fn 133main() -> i32");
auto f = p.function_header(); auto f = p->function_header();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(f, nullptr); ASSERT_EQ(f, nullptr);
EXPECT_EQ(p.error(), "1:4: missing identifier for function"); EXPECT_EQ(p->error(), "1:4: missing identifier for function");
} }
TEST_F(ParserImplTest, FunctionHeader_MissingParenLeft) { TEST_F(ParserImplTest, FunctionHeader_MissingParenLeft) {
ParserImpl p{"fn main) -> i32"}; auto p = parser("fn main) -> i32");
auto f = p.function_header(); auto f = p->function_header();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(f, nullptr); ASSERT_EQ(f, nullptr);
EXPECT_EQ(p.error(), "1:8: missing ( for function declaration"); EXPECT_EQ(p->error(), "1:8: missing ( for function declaration");
} }
TEST_F(ParserImplTest, FunctionHeader_InvalidParamList) { TEST_F(ParserImplTest, FunctionHeader_InvalidParamList) {
ParserImpl p{"fn main(a :i32,) -> i32"}; auto p = parser("fn main(a :i32,) -> i32");
auto f = p.function_header(); auto f = p->function_header();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(f, nullptr); ASSERT_EQ(f, nullptr);
EXPECT_EQ(p.error(), "1:15: found , but no variable declaration"); EXPECT_EQ(p->error(), "1:15: found , but no variable declaration");
} }
TEST_F(ParserImplTest, FunctionHeader_MissingParenRight) { TEST_F(ParserImplTest, FunctionHeader_MissingParenRight) {
ParserImpl p{"fn main( -> i32"}; auto p = parser("fn main( -> i32");
auto f = p.function_header(); auto f = p->function_header();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(f, nullptr); ASSERT_EQ(f, nullptr);
EXPECT_EQ(p.error(), "1:10: missing ) for function declaration"); EXPECT_EQ(p->error(), "1:10: missing ) for function declaration");
} }
TEST_F(ParserImplTest, FunctionHeader_MissingArrow) { TEST_F(ParserImplTest, FunctionHeader_MissingArrow) {
ParserImpl p{"fn main() i32"}; auto p = parser("fn main() i32");
auto f = p.function_header(); auto f = p->function_header();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(f, nullptr); ASSERT_EQ(f, nullptr);
EXPECT_EQ(p.error(), "1:11: missing -> for function declaration"); EXPECT_EQ(p->error(), "1:11: missing -> for function declaration");
} }
TEST_F(ParserImplTest, FunctionHeader_InvalidReturnType) { TEST_F(ParserImplTest, FunctionHeader_InvalidReturnType) {
ParserImpl p{"fn main() -> invalid"}; auto p = parser("fn main() -> invalid");
auto f = p.function_header(); auto f = p->function_header();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(f, nullptr); ASSERT_EQ(f, nullptr);
EXPECT_EQ(p.error(), "1:14: unknown type alias 'invalid'"); EXPECT_EQ(p->error(), "1:14: unknown type alias 'invalid'");
} }
TEST_F(ParserImplTest, FunctionHeader_MissingReturnType) { TEST_F(ParserImplTest, FunctionHeader_MissingReturnType) {
ParserImpl p{"fn main() ->"}; auto p = parser("fn main() ->");
auto f = p.function_header(); auto f = p->function_header();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(f, nullptr); ASSERT_EQ(f, nullptr);
EXPECT_EQ(p.error(), "1:13: unable to determine function return type"); EXPECT_EQ(p->error(), "1:13: unable to determine function return type");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -19,45 +19,38 @@
#include "src/ast/type/vector_type.h" #include "src/ast/type/vector_type.h"
#include "src/ast/type/void_type.h" #include "src/ast/type/void_type.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
#include "src/type_manager.h" #include "src/type_manager.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, FunctionTypeDecl_Void) { TEST_F(ParserImplTest, FunctionTypeDecl_Void) {
auto tm = TypeManager::Instance(); auto v = tm()->Get(std::make_unique<ast::type::VoidType>());
auto v = tm->Get(std::make_unique<ast::type::VoidType>());
ParserImpl p{"void"}; auto p = parser("void");
auto e = p.function_type_decl(); auto e = p->function_type_decl();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e, v); ASSERT_EQ(e, v);
TypeManager::Destroy();
} }
TEST_F(ParserImplTest, FunctionTypeDecl_Type) { TEST_F(ParserImplTest, FunctionTypeDecl_Type) {
auto tm = TypeManager::Instance(); auto f32 = tm()->Get(std::make_unique<ast::type::F32Type>());
auto f32 = tm->Get(std::make_unique<ast::type::F32Type>()); auto vec2 = tm()->Get(std::make_unique<ast::type::VectorType>(f32, 2));
auto vec2 = tm->Get(std::make_unique<ast::type::VectorType>(f32, 2));
ParserImpl p{"vec2<f32>"}; auto p = parser("vec2<f32>");
auto e = p.function_type_decl(); auto e = p->function_type_decl();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e, vec2); ASSERT_EQ(e, vec2);
TypeManager::Destroy();
} }
TEST_F(ParserImplTest, FunctionTypeDecl_InvalidType) { TEST_F(ParserImplTest, FunctionTypeDecl_InvalidType) {
ParserImpl p{"vec2<invalid>"}; auto p = parser("vec2<invalid>");
auto e = p.function_type_decl(); auto e = p->function_type_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:6: unknown type alias 'invalid'"); EXPECT_EQ(p->error(), "1:6: unknown type alias 'invalid'");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -16,17 +16,16 @@
#include "src/ast/decorated_variable.h" #include "src/ast/decorated_variable.h"
#include "src/ast/variable_decoration.h" #include "src/ast/variable_decoration.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, GlobalConstantDecl) { TEST_F(ParserImplTest, GlobalConstantDecl) {
ParserImpl p{"const a : f32 = 1."}; auto p = parser("const a : f32 = 1.");
auto e = p.global_constant_decl(); auto e = p->global_constant_decl();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
EXPECT_TRUE(e->is_const()); EXPECT_TRUE(e->is_const());
@ -39,35 +38,35 @@ TEST_F(ParserImplTest, GlobalConstantDecl) {
} }
TEST_F(ParserImplTest, GlobalConstantDecl_MissingEqual) { TEST_F(ParserImplTest, GlobalConstantDecl_MissingEqual) {
ParserImpl p{"const a: f32 1."}; auto p = parser("const a: f32 1.");
auto e = p.global_constant_decl(); auto e = p->global_constant_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:14: missing = for const declaration"); EXPECT_EQ(p->error(), "1:14: missing = for const declaration");
} }
TEST_F(ParserImplTest, GlobalConstantDecl_InvalidVariable) { TEST_F(ParserImplTest, GlobalConstantDecl_InvalidVariable) {
ParserImpl p{"const a: invalid = 1."}; auto p = parser("const a: invalid = 1.");
auto e = p.global_constant_decl(); auto e = p->global_constant_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:10: unknown type alias 'invalid'"); EXPECT_EQ(p->error(), "1:10: unknown type alias 'invalid'");
} }
TEST_F(ParserImplTest, GlobalConstantDecl_InvalidExpression) { TEST_F(ParserImplTest, GlobalConstantDecl_InvalidExpression) {
ParserImpl p{"const a: f32 = if (a) {}"}; auto p = parser("const a: f32 = if (a) {}");
auto e = p.global_constant_decl(); auto e = p->global_constant_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:16: unable to parse const literal"); EXPECT_EQ(p->error(), "1:16: unable to parse const literal");
} }
TEST_F(ParserImplTest, GlobalConstantDecl_MissingExpression) { TEST_F(ParserImplTest, GlobalConstantDecl_MissingExpression) {
ParserImpl p{"const a: f32 ="}; auto p = parser("const a: f32 =");
auto e = p.global_constant_decl(); auto e = p->global_constant_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:15: unable to parse const literal"); EXPECT_EQ(p->error(), "1:15: unable to parse const literal");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -14,25 +14,24 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, GlobalDecl_Semicolon) { TEST_F(ParserImplTest, GlobalDecl_Semicolon) {
ParserImpl p(";"); auto p = parser(";");
p.global_decl(); p->global_decl();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
} }
TEST_F(ParserImplTest, GlobalDecl_Import) { TEST_F(ParserImplTest, GlobalDecl_Import) {
ParserImpl p{R"(import "GLSL.std.430" as glsl;)"}; auto p = parser(R"(import "GLSL.std.430" as glsl;)");
p.global_decl(); p->global_decl();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
auto m = p.module(); auto m = p->module();
ASSERT_EQ(1, m.imports().size()); ASSERT_EQ(1, m.imports().size());
const auto& import = m.imports()[0]; const auto& import = m.imports()[0];
@ -41,27 +40,27 @@ TEST_F(ParserImplTest, GlobalDecl_Import) {
} }
TEST_F(ParserImplTest, GlobalDecl_Import_Invalid) { TEST_F(ParserImplTest, GlobalDecl_Import_Invalid) {
ParserImpl p{R"(import as glsl;)"}; auto p = parser(R"(import as glsl;)");
p.global_decl(); p->global_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:8: missing path for import"); EXPECT_EQ(p->error(), "1:8: missing path for import");
} }
TEST_F(ParserImplTest, GlobalDecl_Import_Invalid_MissingSemicolon) { TEST_F(ParserImplTest, GlobalDecl_Import_Invalid_MissingSemicolon) {
ParserImpl p{R"(import "GLSL.std.430" as glsl)"}; auto p = parser(R"(import "GLSL.std.430" as glsl)");
p.global_decl(); p->global_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:30: missing ';' for import"); EXPECT_EQ(p->error(), "1:30: missing ';' for import");
} }
TEST_F(ParserImplTest, GlobalDecl_GlobalVariable) { TEST_F(ParserImplTest, GlobalDecl_GlobalVariable) {
ParserImpl p{"var<out> a : vec2<i32> = vec2<i32>(1, 2);"}; auto p = parser("var<out> a : vec2<i32> = vec2<i32>(1, 2);");
p.global_decl(); p->global_decl();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
auto m = p.module(); auto m = p->module();
ASSERT_EQ(m.global_variables().size(), 1); ASSERT_EQ(m.global_variables().size(), 1);
auto v = m.global_variables()[0].get(); auto v = m.global_variables()[0].get();
@ -69,25 +68,25 @@ TEST_F(ParserImplTest, GlobalDecl_GlobalVariable) {
} }
TEST_F(ParserImplTest, GlobalDecl_GlobalVariable_Invalid) { TEST_F(ParserImplTest, GlobalDecl_GlobalVariable_Invalid) {
ParserImpl p{"var<out> a : vec2<invalid>;"}; auto p = parser("var<out> a : vec2<invalid>;");
p.global_decl(); p->global_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:19: unknown type alias 'invalid'"); EXPECT_EQ(p->error(), "1:19: unknown type alias 'invalid'");
} }
TEST_F(ParserImplTest, GlobalDecl_GlobalVariable_MissingSemicolon) { TEST_F(ParserImplTest, GlobalDecl_GlobalVariable_MissingSemicolon) {
ParserImpl p{"var<out> a : vec2<i32>"}; auto p = parser("var<out> a : vec2<i32>");
p.global_decl(); p->global_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:23: missing ';' for variable declaration"); EXPECT_EQ(p->error(), "1:23: missing ';' for variable declaration");
} }
TEST_F(ParserImplTest, GlobalDecl_GlobalConstant) { TEST_F(ParserImplTest, GlobalDecl_GlobalConstant) {
ParserImpl p{"const a : i32 = 2;"}; auto p = parser("const a : i32 = 2;");
p.global_decl(); p->global_decl();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
auto m = p.module(); auto m = p->module();
ASSERT_EQ(m.global_variables().size(), 1); ASSERT_EQ(m.global_variables().size(), 1);
auto v = m.global_variables()[0].get(); auto v = m.global_variables()[0].get();
@ -95,82 +94,82 @@ TEST_F(ParserImplTest, GlobalDecl_GlobalConstant) {
} }
TEST_F(ParserImplTest, GlobalDecl_GlobalConstant_Invalid) { TEST_F(ParserImplTest, GlobalDecl_GlobalConstant_Invalid) {
ParserImpl p{"const a : vec2<i32>;"}; auto p = parser("const a : vec2<i32>;");
p.global_decl(); p->global_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:20: missing = for const declaration"); EXPECT_EQ(p->error(), "1:20: missing = for const declaration");
} }
TEST_F(ParserImplTest, GlobalDecl_GlobalConstant_MissingSemicolon) { TEST_F(ParserImplTest, GlobalDecl_GlobalConstant_MissingSemicolon) {
ParserImpl p{"const a : vec2<i32> = vec2<i32>(1, 2)"}; auto p = parser("const a : vec2<i32> = vec2<i32>(1, 2)");
p.global_decl(); p->global_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:38: missing ';' for constant declaration"); EXPECT_EQ(p->error(), "1:38: missing ';' for constant declaration");
} }
TEST_F(ParserImplTest, GlobalDecl_EntryPoint) { TEST_F(ParserImplTest, GlobalDecl_EntryPoint) {
ParserImpl p{"entry_point vertex = main;"}; auto p = parser("entry_point vertex = main;");
p.global_decl(); p->global_decl();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
auto m = p.module(); auto m = p->module();
ASSERT_EQ(m.entry_points().size(), 1); ASSERT_EQ(m.entry_points().size(), 1);
EXPECT_EQ(m.entry_points()[0]->name(), "main"); EXPECT_EQ(m.entry_points()[0]->name(), "main");
} }
TEST_F(ParserImplTest, GlobalDecl_EntryPoint_Invalid) { TEST_F(ParserImplTest, GlobalDecl_EntryPoint_Invalid) {
ParserImpl p{"entry_point main;"}; auto p = parser("entry_point main;");
p.global_decl(); p->global_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:13: missing pipeline stage for entry point"); EXPECT_EQ(p->error(), "1:13: missing pipeline stage for entry point");
} }
TEST_F(ParserImplTest, GlobalDecl_EntryPoint_MissingSemicolon) { TEST_F(ParserImplTest, GlobalDecl_EntryPoint_MissingSemicolon) {
ParserImpl p{"entry_point vertex = main"}; auto p = parser("entry_point vertex = main");
p.global_decl(); p->global_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:26: missing ';' for entry point"); EXPECT_EQ(p->error(), "1:26: missing ';' for entry point");
} }
TEST_F(ParserImplTest, GlobalDecl_TypeAlias) { TEST_F(ParserImplTest, GlobalDecl_TypeAlias) {
ParserImpl p{"type A = i32;"}; auto p = parser("type A = i32;");
p.global_decl(); p->global_decl();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
auto m = p.module(); auto m = p->module();
ASSERT_EQ(m.alias_types().size(), 1); ASSERT_EQ(m.alias_types().size(), 1);
EXPECT_EQ(m.alias_types()[0]->name(), "A"); EXPECT_EQ(m.alias_types()[0]->name(), "A");
} }
TEST_F(ParserImplTest, GlobalDecl_TypeAlias_Invalid) { TEST_F(ParserImplTest, GlobalDecl_TypeAlias_Invalid) {
ParserImpl p{"type A = invalid;"}; auto p = parser("type A = invalid;");
p.global_decl(); p->global_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:10: unknown type alias 'invalid'"); EXPECT_EQ(p->error(), "1:10: unknown type alias 'invalid'");
} }
TEST_F(ParserImplTest, GlobalDecl_TypeAlias_MissingSemicolon) { TEST_F(ParserImplTest, GlobalDecl_TypeAlias_MissingSemicolon) {
ParserImpl p{"type A = i32"}; auto p = parser("type A = i32");
p.global_decl(); p->global_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:13: missing ';' for type alias"); EXPECT_EQ(p->error(), "1:13: missing ';' for type alias");
} }
TEST_F(ParserImplTest, GlobalDecl_Function) { TEST_F(ParserImplTest, GlobalDecl_Function) {
ParserImpl p{"fn main() -> void { return; }"}; auto p = parser("fn main() -> void { return; }");
p.global_decl(); p->global_decl();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
auto m = p.module(); auto m = p->module();
ASSERT_EQ(m.functions().size(), 1); ASSERT_EQ(m.functions().size(), 1);
EXPECT_EQ(m.functions()[0]->name(), "main"); EXPECT_EQ(m.functions()[0]->name(), "main");
} }
TEST_F(ParserImplTest, GlobalDecl_Function_Invalid) { TEST_F(ParserImplTest, GlobalDecl_Function_Invalid) {
ParserImpl p{"fn main() -> { return; }"}; auto p = parser("fn main() -> { return; }");
p.global_decl(); p->global_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:14: unable to determine function return type"); EXPECT_EQ(p->error(), "1:14: unable to determine function return type");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -16,17 +16,16 @@
#include "src/ast/decorated_variable.h" #include "src/ast/decorated_variable.h"
#include "src/ast/variable_decoration.h" #include "src/ast/variable_decoration.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, GlobalVariableDecl_WithoutInitializer) { TEST_F(ParserImplTest, GlobalVariableDecl_WithoutInitializer) {
ParserImpl p{"var<out> a : f32"}; auto p = parser("var<out> a : f32");
auto e = p.global_variable_decl(); auto e = p->global_variable_decl();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
EXPECT_EQ(e->name(), "a"); EXPECT_EQ(e->name(), "a");
@ -38,9 +37,9 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithoutInitializer) {
} }
TEST_F(ParserImplTest, GlobalVariableDecl_WithInitializer) { TEST_F(ParserImplTest, GlobalVariableDecl_WithInitializer) {
ParserImpl p{"var<out> a : f32 = 1."}; auto p = parser("var<out> a : f32 = 1.");
auto e = p.global_variable_decl(); auto e = p->global_variable_decl();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
EXPECT_EQ(e->name(), "a"); EXPECT_EQ(e->name(), "a");
@ -55,9 +54,9 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithInitializer) {
} }
TEST_F(ParserImplTest, GlobalVariableDecl_WithDecoration) { TEST_F(ParserImplTest, GlobalVariableDecl_WithDecoration) {
ParserImpl p{"[[binding 2, set 1]] var<out> a : f32"}; auto p = parser("[[binding 2, set 1]] var<out> a : f32");
auto e = p.global_variable_decl(); auto e = p->global_variable_decl();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsDecorated()); ASSERT_TRUE(e->IsDecorated());
@ -78,27 +77,27 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithDecoration) {
} }
TEST_F(ParserImplTest, GlobalVariableDecl_InvalidDecoration) { TEST_F(ParserImplTest, GlobalVariableDecl_InvalidDecoration) {
ParserImpl p{"[[binding]] var<out> a : f32"}; auto p = parser("[[binding]] var<out> a : f32");
auto e = p.global_variable_decl(); auto e = p->global_variable_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:10: invalid value for binding decoration"); EXPECT_EQ(p->error(), "1:10: invalid value for binding decoration");
} }
TEST_F(ParserImplTest, GlobalVariableDecl_InvalidConstExpr) { TEST_F(ParserImplTest, GlobalVariableDecl_InvalidConstExpr) {
ParserImpl p{"var<out> a : f32 = if (a) {}"}; auto p = parser("var<out> a : f32 = if (a) {}");
auto e = p.global_variable_decl(); auto e = p->global_variable_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:20: unable to parse const literal"); EXPECT_EQ(p->error(), "1:20: unable to parse const literal");
} }
TEST_F(ParserImplTest, GlobalVariableDecl_InvalidVariableDecl) { TEST_F(ParserImplTest, GlobalVariableDecl_InvalidVariableDecl) {
ParserImpl p{"var<invalid> a : f32;"}; auto p = parser("var<invalid> a : f32;");
auto e = p.global_variable_decl(); auto e = p->global_variable_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:5: invalid storage class for variable decoration"); EXPECT_EQ(p->error(), "1:5: invalid storage class for variable decoration");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -16,17 +16,16 @@
#include "src/ast/else_statement.h" #include "src/ast/else_statement.h"
#include "src/ast/if_statement.h" #include "src/ast/if_statement.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, IfStmt) { TEST_F(ParserImplTest, IfStmt) {
ParserImpl p{"if (a == 4) { a = b; c = d; }"}; auto p = parser("if (a == 4) { a = b; c = d; }");
auto e = p.if_stmt(); auto e = p->if_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsIf()); ASSERT_TRUE(e->IsIf());
@ -38,9 +37,9 @@ TEST_F(ParserImplTest, IfStmt) {
} }
TEST_F(ParserImplTest, IfStmt_WithElse) { TEST_F(ParserImplTest, IfStmt_WithElse) {
ParserImpl p{"if (a == 4) { a = b; c = d; } elseif(c) { d = 2; } else {}"}; auto p = parser("if (a == 4) { a = b; c = d; } elseif(c) { d = 2; } else {}");
auto e = p.if_stmt(); auto e = p->if_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsIf()); ASSERT_TRUE(e->IsIf());
@ -58,16 +57,16 @@ TEST_F(ParserImplTest, IfStmt_WithElse) {
} }
TEST_F(ParserImplTest, IfStmt_WithPremerge) { TEST_F(ParserImplTest, IfStmt_WithPremerge) {
ParserImpl p{R"(if (a == 4) { auto p = parser(R"(if (a == 4) {
a = b; a = b;
c = d; c = d;
} else { } else {
d = 2; d = 2;
} premerge { } premerge {
a = 2; a = 2;
})"}; })");
auto e = p.if_stmt(); auto e = p->if_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsIf()); ASSERT_TRUE(e->IsIf());
@ -83,59 +82,59 @@ TEST_F(ParserImplTest, IfStmt_WithPremerge) {
} }
TEST_F(ParserImplTest, IfStmt_InvalidCondition) { TEST_F(ParserImplTest, IfStmt_InvalidCondition) {
ParserImpl p{"if (a = 3) {}"}; auto p = parser("if (a = 3) {}");
auto e = p.if_stmt(); auto e = p->if_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:7: expected )"); EXPECT_EQ(p->error(), "1:7: expected )");
} }
TEST_F(ParserImplTest, IfStmt_MissingCondition) { TEST_F(ParserImplTest, IfStmt_MissingCondition) {
ParserImpl p{"if {}"}; auto p = parser("if {}");
auto e = p.if_stmt(); auto e = p->if_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:4: expected ("); EXPECT_EQ(p->error(), "1:4: expected (");
} }
TEST_F(ParserImplTest, IfStmt_InvalidBody) { TEST_F(ParserImplTest, IfStmt_InvalidBody) {
ParserImpl p{"if (a) { fn main() -> void {}}"}; auto p = parser("if (a) { fn main() -> void {}}");
auto e = p.if_stmt(); auto e = p->if_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:10: missing }"); EXPECT_EQ(p->error(), "1:10: missing }");
} }
TEST_F(ParserImplTest, IfStmt_MissingBody) { TEST_F(ParserImplTest, IfStmt_MissingBody) {
ParserImpl p{"if (a)"}; auto p = parser("if (a)");
auto e = p.if_stmt(); auto e = p->if_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:7: missing {"); EXPECT_EQ(p->error(), "1:7: missing {");
} }
TEST_F(ParserImplTest, IfStmt_InvalidElseif) { TEST_F(ParserImplTest, IfStmt_InvalidElseif) {
ParserImpl p{"if (a) {} elseif (a) { fn main() -> a{}}"}; auto p = parser("if (a) {} elseif (a) { fn main() -> a{}}");
auto e = p.if_stmt(); auto e = p->if_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:24: missing }"); EXPECT_EQ(p->error(), "1:24: missing }");
} }
TEST_F(ParserImplTest, IfStmt_InvalidElse) { TEST_F(ParserImplTest, IfStmt_InvalidElse) {
ParserImpl p{"if (a) {} else { fn main() -> a{}}"}; auto p = parser("if (a) {} else { fn main() -> a{}}");
auto e = p.if_stmt(); auto e = p->if_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:18: missing }"); EXPECT_EQ(p->error(), "1:18: missing }");
} }
TEST_F(ParserImplTest, IfStmt_InvalidPremerge) { TEST_F(ParserImplTest, IfStmt_InvalidPremerge) {
ParserImpl p{"if (a) {} else {} premerge { fn main() -> a{}}"}; auto p = parser("if (a) {} else {} premerge { fn main() -> a{}}");
auto e = p.if_stmt(); auto e = p->if_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:30: missing }"); EXPECT_EQ(p->error(), "1:30: missing }");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -14,19 +14,18 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, ImportDecl_Import) { TEST_F(ParserImplTest, ImportDecl_Import) {
ParserImpl p{R"(import "GLSL.std.450" as glsl)"}; auto p = parser(R"(import "GLSL.std.450" as glsl)");
auto import = p.import_decl(); auto import = p->import_decl();
ASSERT_NE(import, nullptr); ASSERT_NE(import, nullptr);
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_EQ("GLSL.std.450", import->path()); EXPECT_EQ("GLSL.std.450", import->path());
EXPECT_EQ("glsl", import->name()); EXPECT_EQ("glsl", import->name());
@ -35,59 +34,59 @@ TEST_F(ParserImplTest, ImportDecl_Import) {
} }
TEST_F(ParserImplTest, ImportDecl_Import_WithNamespace) { TEST_F(ParserImplTest, ImportDecl_Import_WithNamespace) {
ParserImpl p{R"(import "GLSL.std.450" as std::glsl)"}; auto p = parser(R"(import "GLSL.std.450" as std::glsl)");
auto import = p.import_decl(); auto import = p->import_decl();
ASSERT_NE(import, nullptr); ASSERT_NE(import, nullptr);
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_EQ("std::glsl", import->name()); EXPECT_EQ("std::glsl", import->name());
} }
TEST_F(ParserImplTest, ImportDecl_Invalid_MissingPath) { TEST_F(ParserImplTest, ImportDecl_Invalid_MissingPath) {
ParserImpl p{R"(import as glsl)"}; auto p = parser(R"(import as glsl)");
auto import = p.import_decl(); auto import = p->import_decl();
ASSERT_EQ(import, nullptr); ASSERT_EQ(import, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:8: missing path for import"); EXPECT_EQ(p->error(), "1:8: missing path for import");
} }
TEST_F(ParserImplTest, ImportDecl_Invalid_EmptyPath) { TEST_F(ParserImplTest, ImportDecl_Invalid_EmptyPath) {
ParserImpl p{R"(import "" as glsl)"}; auto p = parser(R"(import "" as glsl)");
auto import = p.import_decl(); auto import = p->import_decl();
ASSERT_EQ(import, nullptr); ASSERT_EQ(import, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:8: import path must not be empty"); EXPECT_EQ(p->error(), "1:8: import path must not be empty");
} }
TEST_F(ParserImplTest, ImportDecl_Invalid_NameMissingTerminatingIdentifier) { TEST_F(ParserImplTest, ImportDecl_Invalid_NameMissingTerminatingIdentifier) {
ParserImpl p{R"(import "GLSL.std.450" as glsl::)"}; auto p = parser(R"(import "GLSL.std.450" as glsl::)");
auto import = p.import_decl(); auto import = p->import_decl();
ASSERT_EQ(import, nullptr); ASSERT_EQ(import, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:32: invalid name for import"); EXPECT_EQ(p->error(), "1:32: invalid name for import");
} }
TEST_F(ParserImplTest, ImportDecl_Invalid_NameInvalid) { TEST_F(ParserImplTest, ImportDecl_Invalid_NameInvalid) {
ParserImpl p{R"(import "GLSL.std.450" as 12glsl)"}; auto p = parser(R"(import "GLSL.std.450" as 12glsl)");
auto import = p.import_decl(); auto import = p->import_decl();
ASSERT_EQ(import, nullptr); ASSERT_EQ(import, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:26: invalid name for import"); EXPECT_EQ(p->error(), "1:26: invalid name for import");
} }
TEST_F(ParserImplTest, ImportDecl_Invalid_MissingName) { TEST_F(ParserImplTest, ImportDecl_Invalid_MissingName) {
ParserImpl p{R"(import "GLSL.std.450" as)"}; auto p = parser(R"(import "GLSL.std.450" as)");
auto import = p.import_decl(); auto import = p->import_decl();
ASSERT_EQ(import, nullptr); ASSERT_EQ(import, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:25: missing name for import"); EXPECT_EQ(p->error(), "1:25: missing name for import");
} }
TEST_F(ParserImplTest, ImportDecl_Invalid_MissingAs) { TEST_F(ParserImplTest, ImportDecl_Invalid_MissingAs) {
ParserImpl p{R"(import "GLSL.std.450" glsl)"}; auto p = parser(R"(import "GLSL.std.450" glsl)");
auto import = p.import_decl(); auto import = p->import_decl();
ASSERT_EQ(import, nullptr); ASSERT_EQ(import, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:23: missing 'as' for import"); EXPECT_EQ(p->error(), "1:23: missing 'as' for import");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -18,17 +18,16 @@
#include "src/ast/identifier_expression.h" #include "src/ast/identifier_expression.h"
#include "src/ast/relational_expression.h" #include "src/ast/relational_expression.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, InclusiveOrExpression_Parses) { TEST_F(ParserImplTest, InclusiveOrExpression_Parses) {
ParserImpl p{"a | true"}; auto p = parser("a | true");
auto e = p.inclusive_or_expression(); auto e = p->inclusive_or_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRelational()); ASSERT_TRUE(e->IsRelational());
@ -48,24 +47,24 @@ TEST_F(ParserImplTest, InclusiveOrExpression_Parses) {
} }
TEST_F(ParserImplTest, InclusiveOrExpression_InvalidLHS) { TEST_F(ParserImplTest, InclusiveOrExpression_InvalidLHS) {
ParserImpl p{"if (a) {} | true"}; auto p = parser("if (a) {} | true");
auto e = p.inclusive_or_expression(); auto e = p->inclusive_or_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
} }
TEST_F(ParserImplTest, InclusiveOrExpression_InvalidRHS) { TEST_F(ParserImplTest, InclusiveOrExpression_InvalidRHS) {
ParserImpl p{"true | if (a) {}"}; auto p = parser("true | if (a) {}");
auto e = p.inclusive_or_expression(); auto e = p->inclusive_or_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: unable to parse right side of | expression"); EXPECT_EQ(p->error(), "1:8: unable to parse right side of | expression");
} }
TEST_F(ParserImplTest, InclusiveOrExpression_NoOr_ReturnsLHS) { TEST_F(ParserImplTest, InclusiveOrExpression_NoOr_ReturnsLHS) {
ParserImpl p{"a true"}; auto p = parser("a true");
auto e = p.inclusive_or_expression(); auto e = p->inclusive_or_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsIdentifier()); ASSERT_TRUE(e->IsIdentifier());
} }

View File

@ -18,17 +18,16 @@
#include "src/ast/identifier_expression.h" #include "src/ast/identifier_expression.h"
#include "src/ast/relational_expression.h" #include "src/ast/relational_expression.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, LogicalAndExpression_Parses) { TEST_F(ParserImplTest, LogicalAndExpression_Parses) {
ParserImpl p{"a && true"}; auto p = parser("a && true");
auto e = p.logical_and_expression(); auto e = p->logical_and_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRelational()); ASSERT_TRUE(e->IsRelational());
@ -48,24 +47,24 @@ TEST_F(ParserImplTest, LogicalAndExpression_Parses) {
} }
TEST_F(ParserImplTest, LogicalAndExpression_InvalidLHS) { TEST_F(ParserImplTest, LogicalAndExpression_InvalidLHS) {
ParserImpl p{"if (a) {} && true"}; auto p = parser("if (a) {} && true");
auto e = p.logical_and_expression(); auto e = p->logical_and_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
} }
TEST_F(ParserImplTest, LogicalAndExpression_InvalidRHS) { TEST_F(ParserImplTest, LogicalAndExpression_InvalidRHS) {
ParserImpl p{"true && if (a) {}"}; auto p = parser("true && if (a) {}");
auto e = p.logical_and_expression(); auto e = p->logical_and_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:9: unable to parse right side of && expression"); EXPECT_EQ(p->error(), "1:9: unable to parse right side of && expression");
} }
TEST_F(ParserImplTest, LogicalAndExpression_NoOr_ReturnsLHS) { TEST_F(ParserImplTest, LogicalAndExpression_NoOr_ReturnsLHS) {
ParserImpl p{"a true"}; auto p = parser("a true");
auto e = p.logical_and_expression(); auto e = p->logical_and_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsIdentifier()); ASSERT_TRUE(e->IsIdentifier());
} }

View File

@ -18,17 +18,16 @@
#include "src/ast/identifier_expression.h" #include "src/ast/identifier_expression.h"
#include "src/ast/relational_expression.h" #include "src/ast/relational_expression.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, LogicalOrExpression_Parses) { TEST_F(ParserImplTest, LogicalOrExpression_Parses) {
ParserImpl p{"a || true"}; auto p = parser("a || true");
auto e = p.logical_or_expression(); auto e = p->logical_or_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRelational()); ASSERT_TRUE(e->IsRelational());
@ -48,24 +47,24 @@ TEST_F(ParserImplTest, LogicalOrExpression_Parses) {
} }
TEST_F(ParserImplTest, LogicalOrExpression_InvalidLHS) { TEST_F(ParserImplTest, LogicalOrExpression_InvalidLHS) {
ParserImpl p{"if (a) {} || true"}; auto p = parser("if (a) {} || true");
auto e = p.logical_or_expression(); auto e = p->logical_or_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
} }
TEST_F(ParserImplTest, LogicalOrExpression_InvalidRHS) { TEST_F(ParserImplTest, LogicalOrExpression_InvalidRHS) {
ParserImpl p{"true || if (a) {}"}; auto p = parser("true || if (a) {}");
auto e = p.logical_or_expression(); auto e = p->logical_or_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:9: unable to parse right side of || expression"); EXPECT_EQ(p->error(), "1:9: unable to parse right side of || expression");
} }
TEST_F(ParserImplTest, LogicalOrExpression_NoOr_ReturnsLHS) { TEST_F(ParserImplTest, LogicalOrExpression_NoOr_ReturnsLHS) {
ParserImpl p{"a true"}; auto p = parser("a true");
auto e = p.logical_or_expression(); auto e = p->logical_or_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsIdentifier()); ASSERT_TRUE(e->IsIdentifier());
} }

View File

@ -14,17 +14,16 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, LoopStmt_BodyNoContinuing) { TEST_F(ParserImplTest, LoopStmt_BodyNoContinuing) {
ParserImpl p{"loop { nop; }"}; auto p = parser("loop { nop; }");
auto e = p.loop_stmt(); auto e = p->loop_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_EQ(e->body().size(), 1); ASSERT_EQ(e->body().size(), 1);
@ -34,9 +33,9 @@ TEST_F(ParserImplTest, LoopStmt_BodyNoContinuing) {
} }
TEST_F(ParserImplTest, LoopStmt_BodyWithContinuing) { TEST_F(ParserImplTest, LoopStmt_BodyWithContinuing) {
ParserImpl p{"loop { nop; continuing { kill; }}"}; auto p = parser("loop { nop; continuing { kill; }}");
auto e = p.loop_stmt(); auto e = p->loop_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_EQ(e->body().size(), 1); ASSERT_EQ(e->body().size(), 1);
@ -47,18 +46,18 @@ TEST_F(ParserImplTest, LoopStmt_BodyWithContinuing) {
} }
TEST_F(ParserImplTest, LoopStmt_NoBodyNoContinuing) { TEST_F(ParserImplTest, LoopStmt_NoBodyNoContinuing) {
ParserImpl p{"loop { }"}; auto p = parser("loop { }");
auto e = p.loop_stmt(); auto e = p->loop_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_EQ(e->body().size(), 0); ASSERT_EQ(e->body().size(), 0);
ASSERT_EQ(e->continuing().size(), 0); ASSERT_EQ(e->continuing().size(), 0);
} }
TEST_F(ParserImplTest, LoopStmt_NoBodyWithContinuing) { TEST_F(ParserImplTest, LoopStmt_NoBodyWithContinuing) {
ParserImpl p{"loop { continuing { kill; }}"}; auto p = parser("loop { continuing { kill; }}");
auto e = p.loop_stmt(); auto e = p->loop_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_EQ(e->body().size(), 0); ASSERT_EQ(e->body().size(), 0);
ASSERT_EQ(e->continuing().size(), 1); ASSERT_EQ(e->continuing().size(), 1);
@ -66,35 +65,35 @@ TEST_F(ParserImplTest, LoopStmt_NoBodyWithContinuing) {
} }
TEST_F(ParserImplTest, LoopStmt_MissingBracketLeft) { TEST_F(ParserImplTest, LoopStmt_MissingBracketLeft) {
ParserImpl p{"loop kill; }"}; auto p = parser("loop kill; }");
auto e = p.loop_stmt(); auto e = p->loop_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:6: missing { for loop"); EXPECT_EQ(p->error(), "1:6: missing { for loop");
} }
TEST_F(ParserImplTest, LoopStmt_MissingBracketRight) { TEST_F(ParserImplTest, LoopStmt_MissingBracketRight) {
ParserImpl p{"loop { kill; "}; auto p = parser("loop { kill; ");
auto e = p.loop_stmt(); auto e = p->loop_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:14: missing } for loop"); EXPECT_EQ(p->error(), "1:14: missing } for loop");
} }
TEST_F(ParserImplTest, LoopStmt_InvalidStatements) { TEST_F(ParserImplTest, LoopStmt_InvalidStatements) {
ParserImpl p{"loop { kill }"}; auto p = parser("loop { kill }");
auto e = p.loop_stmt(); auto e = p->loop_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:13: missing ;"); EXPECT_EQ(p->error(), "1:13: missing ;");
} }
TEST_F(ParserImplTest, LoopStmt_InvalidContinuing) { TEST_F(ParserImplTest, LoopStmt_InvalidContinuing) {
ParserImpl p{"loop { continuing { kill }}"}; auto p = parser("loop { continuing { kill }}");
auto e = p.loop_stmt(); auto e = p->loop_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:26: missing ;"); EXPECT_EQ(p->error(), "1:26: missing ;");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -18,17 +18,16 @@
#include "src/ast/identifier_expression.h" #include "src/ast/identifier_expression.h"
#include "src/ast/relational_expression.h" #include "src/ast/relational_expression.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Multiply) { TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Multiply) {
ParserImpl p{"a * true"}; auto p = parser("a * true");
auto e = p.multiplicative_expression(); auto e = p->multiplicative_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRelational()); ASSERT_TRUE(e->IsRelational());
@ -48,9 +47,9 @@ TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Multiply) {
} }
TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Divide) { TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Divide) {
ParserImpl p{"a / true"}; auto p = parser("a / true");
auto e = p.multiplicative_expression(); auto e = p->multiplicative_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRelational()); ASSERT_TRUE(e->IsRelational());
@ -70,9 +69,9 @@ TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Divide) {
} }
TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Modulo) { TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Modulo) {
ParserImpl p{"a % true"}; auto p = parser("a % true");
auto e = p.multiplicative_expression(); auto e = p->multiplicative_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRelational()); ASSERT_TRUE(e->IsRelational());
@ -92,24 +91,24 @@ TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Modulo) {
} }
TEST_F(ParserImplTest, MultiplicativeExpression_InvalidLHS) { TEST_F(ParserImplTest, MultiplicativeExpression_InvalidLHS) {
ParserImpl p{"if (a) {} * true"}; auto p = parser("if (a) {} * true");
auto e = p.multiplicative_expression(); auto e = p->multiplicative_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
} }
TEST_F(ParserImplTest, MultiplicativeExpression_InvalidRHS) { TEST_F(ParserImplTest, MultiplicativeExpression_InvalidRHS) {
ParserImpl p{"true * if (a) {}"}; auto p = parser("true * if (a) {}");
auto e = p.multiplicative_expression(); auto e = p->multiplicative_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: unable to parse right side of * expression"); EXPECT_EQ(p->error(), "1:8: unable to parse right side of * expression");
} }
TEST_F(ParserImplTest, MultiplicativeExpression_NoOr_ReturnsLHS) { TEST_F(ParserImplTest, MultiplicativeExpression_NoOr_ReturnsLHS) {
ParserImpl p{"a true"}; auto p = parser("a true");
auto e = p.multiplicative_expression(); auto e = p->multiplicative_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsIdentifier()); ASSERT_TRUE(e->IsIdentifier());
} }

View File

@ -20,38 +20,33 @@
#include "src/ast/type/vector_type.h" #include "src/ast/type/vector_type.h"
#include "src/ast/variable.h" #include "src/ast/variable.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
#include "src/type_manager.h" #include "src/type_manager.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, ParamList_Single) { TEST_F(ParserImplTest, ParamList_Single) {
auto tm = TypeManager::Instance(); auto i32 = tm()->Get(std::make_unique<ast::type::I32Type>());
auto i32 = tm->Get(std::make_unique<ast::type::I32Type>());
ParserImpl p{"a : i32"}; auto p = parser("a : i32");
auto e = p.param_list(); auto e = p->param_list();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_EQ(e.size(), 1); EXPECT_EQ(e.size(), 1);
EXPECT_EQ(e[0]->name(), "a"); EXPECT_EQ(e[0]->name(), "a");
EXPECT_EQ(e[0]->type(), i32); EXPECT_EQ(e[0]->type(), i32);
TypeManager::Destroy();
} }
TEST_F(ParserImplTest, ParamList_Multiple) { TEST_F(ParserImplTest, ParamList_Multiple) {
auto tm = TypeManager::Instance(); auto i32 = tm()->Get(std::make_unique<ast::type::I32Type>());
auto i32 = tm->Get(std::make_unique<ast::type::I32Type>()); auto f32 = tm()->Get(std::make_unique<ast::type::F32Type>());
auto f32 = tm->Get(std::make_unique<ast::type::F32Type>()); auto vec2 = tm()->Get(std::make_unique<ast::type::VectorType>(f32, 2));
auto vec2 = tm->Get(std::make_unique<ast::type::VectorType>(f32, 2));
ParserImpl p{"a : i32, b: f32, c: vec2<f32>"}; auto p = parser("a : i32, b: f32, c: vec2<f32>");
auto e = p.param_list(); auto e = p->param_list();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_EQ(e.size(), 3); EXPECT_EQ(e.size(), 3);
EXPECT_EQ(e[0]->name(), "a"); EXPECT_EQ(e[0]->name(), "a");
@ -62,22 +57,20 @@ TEST_F(ParserImplTest, ParamList_Multiple) {
EXPECT_EQ(e[2]->name(), "c"); EXPECT_EQ(e[2]->name(), "c");
EXPECT_EQ(e[2]->type(), vec2); EXPECT_EQ(e[2]->type(), vec2);
TypeManager::Destroy();
} }
TEST_F(ParserImplTest, ParamList_Empty) { TEST_F(ParserImplTest, ParamList_Empty) {
ParserImpl p{""}; auto p = parser("");
auto e = p.param_list(); auto e = p->param_list();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_EQ(e.size(), 0); EXPECT_EQ(e.size(), 0);
} }
TEST_F(ParserImplTest, ParamList_HangingComma) { TEST_F(ParserImplTest, ParamList_HangingComma) {
ParserImpl p{"a : i32,"}; auto p = parser("a : i32,");
auto e = p.param_list(); auto e = p->param_list();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:8: found , but no variable declaration"); EXPECT_EQ(p->error(), "1:8: found , but no variable declaration");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -14,51 +14,50 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, ParenRhsStmt) { TEST_F(ParserImplTest, ParenRhsStmt) {
ParserImpl p{"(a + b)"}; auto p = parser("(a + b)");
auto e = p.paren_rhs_stmt(); auto e = p->paren_rhs_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRelational()); ASSERT_TRUE(e->IsRelational());
} }
TEST_F(ParserImplTest, ParenRhsStmt_MissingLeftParen) { TEST_F(ParserImplTest, ParenRhsStmt_MissingLeftParen) {
ParserImpl p{"true)"}; auto p = parser("true)");
auto e = p.paren_rhs_stmt(); auto e = p->paren_rhs_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:1: expected ("); EXPECT_EQ(p->error(), "1:1: expected (");
} }
TEST_F(ParserImplTest, ParenRhsStmt_MissingRightParen) { TEST_F(ParserImplTest, ParenRhsStmt_MissingRightParen) {
ParserImpl p{"(true"}; auto p = parser("(true");
auto e = p.paren_rhs_stmt(); auto e = p->paren_rhs_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:6: expected )"); EXPECT_EQ(p->error(), "1:6: expected )");
} }
TEST_F(ParserImplTest, ParenRhsStmt_InvalidExpression) { TEST_F(ParserImplTest, ParenRhsStmt_InvalidExpression) {
ParserImpl p{"(if (a() {})"}; auto p = parser("(if (a() {})");
auto e = p.paren_rhs_stmt(); auto e = p->paren_rhs_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:2: unable to parse expression"); EXPECT_EQ(p->error(), "1:2: unable to parse expression");
} }
TEST_F(ParserImplTest, ParenRhsStmt_MissingExpression) { TEST_F(ParserImplTest, ParenRhsStmt_MissingExpression) {
ParserImpl p{"()"}; auto p = parser("()");
auto e = p.paren_rhs_stmt(); auto e = p->paren_rhs_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:2: unable to parse expression"); EXPECT_EQ(p->error(), "1:2: unable to parse expression");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -15,12 +15,12 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/ast/pipeline_stage.h" #include "src/ast/pipeline_stage.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
namespace {
using ParserImplTest = testing::Test;
struct PipelineStageData { struct PipelineStageData {
const char* input; const char* input;
@ -30,16 +30,41 @@ inline std::ostream& operator<<(std::ostream& out, PipelineStageData data) {
out << std::string(data.input); out << std::string(data.input);
return out; return out;
} }
using PipelineStageTest = testing::TestWithParam<PipelineStageData>;
class PipelineStageTest : public testing::TestWithParam<PipelineStageData> {
public:
PipelineStageTest() = default;
~PipelineStageTest() = default;
void SetUp() { ctx_.type_mgr = &tm_; }
void TearDown() {
impl_ = nullptr;
ctx_.type_mgr = nullptr;
}
ParserImpl* parser(const std::string& str) {
impl_ = std::make_unique<ParserImpl>(ctx_, str);
return impl_.get();
}
private:
std::unique_ptr<ParserImpl> impl_;
Context ctx_;
TypeManager tm_;
};
} // namespace
TEST_P(PipelineStageTest, Parses) { TEST_P(PipelineStageTest, Parses) {
auto params = GetParam(); auto params = GetParam();
ParserImpl p{params.input}; auto p = parser(params.input);
auto stage = p.pipeline_stage(); auto stage = p->pipeline_stage();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
EXPECT_EQ(stage, params.result); EXPECT_EQ(stage, params.result);
auto t = p.next(); auto t = p->next();
EXPECT_TRUE(t.IsEof()); EXPECT_TRUE(t.IsEof());
} }
INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P(
@ -51,11 +76,11 @@ INSTANTIATE_TEST_SUITE_P(
PipelineStageData{"compute", ast::PipelineStage::kCompute})); PipelineStageData{"compute", ast::PipelineStage::kCompute}));
TEST_F(ParserImplTest, PipelineStage_NoMatch) { TEST_F(ParserImplTest, PipelineStage_NoMatch) {
ParserImpl p{"not-a-stage"}; auto p = parser("not-a-stage");
auto stage = p.pipeline_stage(); auto stage = p->pipeline_stage();
ASSERT_EQ(stage, ast::PipelineStage::kNone); ASSERT_EQ(stage, ast::PipelineStage::kNone);
auto t = p.next(); auto t = p->next();
EXPECT_TRUE(t.IsIdentifier()); EXPECT_TRUE(t.IsIdentifier());
EXPECT_EQ(t.to_str(), "not"); EXPECT_EQ(t.to_str(), "not");
} }

View File

@ -23,17 +23,16 @@
#include "src/ast/unary_method_expression.h" #include "src/ast/unary_method_expression.h"
#include "src/ast/unary_op_expression.h" #include "src/ast/unary_op_expression.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, PostfixExpression_Array_ConstantIndex) { TEST_F(ParserImplTest, PostfixExpression_Array_ConstantIndex) {
ParserImpl p{"a[1]"}; auto p = parser("a[1]");
auto e = p.postfix_expression(); auto e = p->postfix_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsArrayAccessor()); ASSERT_TRUE(e->IsArrayAccessor());
@ -52,9 +51,9 @@ TEST_F(ParserImplTest, PostfixExpression_Array_ConstantIndex) {
} }
TEST_F(ParserImplTest, PostfixExpression_Array_ExpressionIndex) { TEST_F(ParserImplTest, PostfixExpression_Array_ExpressionIndex) {
ParserImpl p{"a[1 + b / 4]"}; auto p = parser("a[1 + b / 4]");
auto e = p.postfix_expression(); auto e = p->postfix_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsArrayAccessor()); ASSERT_TRUE(e->IsArrayAccessor());
@ -69,33 +68,33 @@ TEST_F(ParserImplTest, PostfixExpression_Array_ExpressionIndex) {
} }
TEST_F(ParserImplTest, PostfixExpression_Array_MissingIndex) { TEST_F(ParserImplTest, PostfixExpression_Array_MissingIndex) {
ParserImpl p{"a[]"}; auto p = parser("a[]");
auto e = p.postfix_expression(); auto e = p->postfix_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:3: unable to parse expression inside []"); EXPECT_EQ(p->error(), "1:3: unable to parse expression inside []");
} }
TEST_F(ParserImplTest, PostfixExpression_Array_MissingRightBrace) { TEST_F(ParserImplTest, PostfixExpression_Array_MissingRightBrace) {
ParserImpl p{"a[1"}; auto p = parser("a[1");
auto e = p.postfix_expression(); auto e = p->postfix_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:4: missing ] for array accessor"); EXPECT_EQ(p->error(), "1:4: missing ] for array accessor");
} }
TEST_F(ParserImplTest, PostfixExpression_Array_InvalidIndex) { TEST_F(ParserImplTest, PostfixExpression_Array_InvalidIndex) {
ParserImpl p{"a[if(a() {})]"}; auto p = parser("a[if(a() {})]");
auto e = p.postfix_expression(); auto e = p->postfix_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:3: unable to parse expression inside []"); EXPECT_EQ(p->error(), "1:3: unable to parse expression inside []");
} }
TEST_F(ParserImplTest, PostfixExpression_Call_Empty) { TEST_F(ParserImplTest, PostfixExpression_Call_Empty) {
ParserImpl p{"a()"}; auto p = parser("a()");
auto e = p.postfix_expression(); auto e = p->postfix_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsCall()); ASSERT_TRUE(e->IsCall());
@ -110,9 +109,9 @@ TEST_F(ParserImplTest, PostfixExpression_Call_Empty) {
} }
TEST_F(ParserImplTest, PostfixExpression_Call_WithArgs) { TEST_F(ParserImplTest, PostfixExpression_Call_WithArgs) {
ParserImpl p{"std::test(1, b, 2 + 3 / b)"}; auto p = parser("std::test(1, b, 2 + 3 / b)");
auto e = p.postfix_expression(); auto e = p->postfix_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsCall()); ASSERT_TRUE(e->IsCall());
@ -131,33 +130,33 @@ TEST_F(ParserImplTest, PostfixExpression_Call_WithArgs) {
} }
TEST_F(ParserImplTest, PostfixExpression_Call_InvalidArg) { TEST_F(ParserImplTest, PostfixExpression_Call_InvalidArg) {
ParserImpl p{"a(if(a) {})"}; auto p = parser("a(if(a) {})");
auto e = p.postfix_expression(); auto e = p->postfix_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:3: unable to parse argument expression"); EXPECT_EQ(p->error(), "1:3: unable to parse argument expression");
} }
TEST_F(ParserImplTest, PostfixExpression_Call_HangingComma) { TEST_F(ParserImplTest, PostfixExpression_Call_HangingComma) {
ParserImpl p{"a(b, )"}; auto p = parser("a(b, )");
auto e = p.postfix_expression(); auto e = p->postfix_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:6: unable to parse argument expression after comma"); EXPECT_EQ(p->error(), "1:6: unable to parse argument expression after comma");
} }
TEST_F(ParserImplTest, PostfixExpression_Call_MissingRightParen) { TEST_F(ParserImplTest, PostfixExpression_Call_MissingRightParen) {
ParserImpl p{"a("}; auto p = parser("a(");
auto e = p.postfix_expression(); auto e = p->postfix_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:3: missing ) for call expression"); EXPECT_EQ(p->error(), "1:3: missing ) for call expression");
} }
TEST_F(ParserImplTest, PostfixExpression_MemberAccessor) { TEST_F(ParserImplTest, PostfixExpression_MemberAccessor) {
ParserImpl p{"a.b"}; auto p = parser("a.b");
auto e = p.postfix_expression(); auto e = p->postfix_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsMemberAccessor()); ASSERT_TRUE(e->IsMemberAccessor());
@ -172,25 +171,25 @@ TEST_F(ParserImplTest, PostfixExpression_MemberAccessor) {
} }
TEST_F(ParserImplTest, PostfixExpression_MemberAccesssor_InvalidIdent) { TEST_F(ParserImplTest, PostfixExpression_MemberAccesssor_InvalidIdent) {
ParserImpl p{"a.if"}; auto p = parser("a.if");
auto e = p.postfix_expression(); auto e = p->postfix_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:3: missing identifier for member accessor"); EXPECT_EQ(p->error(), "1:3: missing identifier for member accessor");
} }
TEST_F(ParserImplTest, PostfixExpression_MemberAccessor_MissingIdent) { TEST_F(ParserImplTest, PostfixExpression_MemberAccessor_MissingIdent) {
ParserImpl p{"a."}; auto p = parser("a.");
auto e = p.postfix_expression(); auto e = p->postfix_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:3: missing identifier for member accessor"); EXPECT_EQ(p->error(), "1:3: missing identifier for member accessor");
} }
TEST_F(ParserImplTest, PostfixExpression_NonMatch_returnLHS) { TEST_F(ParserImplTest, PostfixExpression_NonMatch_returnLHS) {
ParserImpl p{"a b"}; auto p = parser("a b");
auto e = p.postfix_expression(); auto e = p->postfix_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsIdentifier()); ASSERT_TRUE(e->IsIdentifier());
} }

View File

@ -14,27 +14,26 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, PremergeStmt) { TEST_F(ParserImplTest, PremergeStmt) {
ParserImpl p{"premerge { nop; }"}; auto p = parser("premerge { nop; }");
auto e = p.premerge_stmt(); auto e = p->premerge_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e.size(), 1); ASSERT_EQ(e.size(), 1);
ASSERT_TRUE(e[0]->IsNop()); ASSERT_TRUE(e[0]->IsNop());
} }
TEST_F(ParserImplTest, PremergeStmt_InvalidBody) { TEST_F(ParserImplTest, PremergeStmt_InvalidBody) {
ParserImpl p{"premerge { nop }"}; auto p = parser("premerge { nop }");
auto e = p.premerge_stmt(); auto e = p->premerge_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e.size(), 0); ASSERT_EQ(e.size(), 0);
EXPECT_EQ(p.error(), "1:16: missing ;"); EXPECT_EQ(p->error(), "1:16: missing ;");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -27,18 +27,17 @@
#include "src/ast/unary_method_expression.h" #include "src/ast/unary_method_expression.h"
#include "src/ast/unary_op_expression.h" #include "src/ast/unary_op_expression.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
#include "src/type_manager.h" #include "src/type_manager.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, PrimaryExpression_Ident) { TEST_F(ParserImplTest, PrimaryExpression_Ident) {
ParserImpl p{"a"}; auto p = parser("a");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsIdentifier()); ASSERT_TRUE(e->IsIdentifier());
auto ident = e->AsIdentifier(); auto ident = e->AsIdentifier();
@ -47,9 +46,9 @@ TEST_F(ParserImplTest, PrimaryExpression_Ident) {
} }
TEST_F(ParserImplTest, PrimaryExpression_Ident_WithNamespace) { TEST_F(ParserImplTest, PrimaryExpression_Ident_WithNamespace) {
ParserImpl p{"a::b::c::d"}; auto p = parser("a::b::c::d");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsIdentifier()); ASSERT_TRUE(e->IsIdentifier());
auto ident = e->AsIdentifier(); auto ident = e->AsIdentifier();
@ -61,17 +60,17 @@ TEST_F(ParserImplTest, PrimaryExpression_Ident_WithNamespace) {
} }
TEST_F(ParserImplTest, PrimaryExpression_Ident_MissingIdent) { TEST_F(ParserImplTest, PrimaryExpression_Ident_MissingIdent) {
ParserImpl p{"a::"}; auto p = parser("a::");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:4: identifier expected"); EXPECT_EQ(p->error(), "1:4: identifier expected");
} }
TEST_F(ParserImplTest, PrimaryExpression_TypeDecl) { TEST_F(ParserImplTest, PrimaryExpression_TypeDecl) {
ParserImpl p{"vec4<i32>(1, 2, 3, 4))"}; auto p = parser("vec4<i32>(1, 2, 3, 4))");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsInitializer()); ASSERT_TRUE(e->IsInitializer());
ASSERT_TRUE(e->AsInitializer()->IsTypeInitializer()); ASSERT_TRUE(e->AsInitializer()->IsTypeInitializer());
@ -105,41 +104,41 @@ TEST_F(ParserImplTest, PrimaryExpression_TypeDecl) {
} }
TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_InvalidTypeDecl) { TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_InvalidTypeDecl) {
ParserImpl p{"vec4<if>(2., 3., 4., 5.)"}; auto p = parser("vec4<if>(2., 3., 4., 5.)");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:6: unable to determine subtype for vector"); EXPECT_EQ(p->error(), "1:6: unable to determine subtype for vector");
} }
TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_MissingLeftParen) { TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_MissingLeftParen) {
ParserImpl p{"vec4<f32> 2., 3., 4., 5.)"}; auto p = parser("vec4<f32> 2., 3., 4., 5.)");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:11: missing ( for type initializer"); EXPECT_EQ(p->error(), "1:11: missing ( for type initializer");
} }
TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_MissingRightParen) { TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_MissingRightParen) {
ParserImpl p{"vec4<f32>(2., 3., 4., 5."}; auto p = parser("vec4<f32>(2., 3., 4., 5.");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:25: missing ) for type initializer"); EXPECT_EQ(p->error(), "1:25: missing ) for type initializer");
} }
TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_InvalidValue) { TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_InvalidValue) {
ParserImpl p{"i32(if(a) {})"}; auto p = parser("i32(if(a) {})");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:5: unable to parse argument expression"); EXPECT_EQ(p->error(), "1:5: unable to parse argument expression");
} }
TEST_F(ParserImplTest, PrimaryExpression_ConstLiteral_True) { TEST_F(ParserImplTest, PrimaryExpression_ConstLiteral_True) {
ParserImpl p{"true"}; auto p = parser("true");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsInitializer()); ASSERT_TRUE(e->IsInitializer());
ASSERT_TRUE(e->AsInitializer()->IsConstInitializer()); ASSERT_TRUE(e->AsInitializer()->IsConstInitializer());
@ -149,44 +148,43 @@ TEST_F(ParserImplTest, PrimaryExpression_ConstLiteral_True) {
} }
TEST_F(ParserImplTest, PrimaryExpression_ParenExpr) { TEST_F(ParserImplTest, PrimaryExpression_ParenExpr) {
ParserImpl p{"(a == b)"}; auto p = parser("(a == b)");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRelational()); ASSERT_TRUE(e->IsRelational());
} }
TEST_F(ParserImplTest, PrimaryExpression_ParenExpr_MissingRightParen) { TEST_F(ParserImplTest, PrimaryExpression_ParenExpr_MissingRightParen) {
ParserImpl p{"(a == b"}; auto p = parser("(a == b");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: expected )"); EXPECT_EQ(p->error(), "1:8: expected )");
} }
TEST_F(ParserImplTest, PrimaryExpression_ParenExpr_MissingExpr) { TEST_F(ParserImplTest, PrimaryExpression_ParenExpr_MissingExpr) {
ParserImpl p{"()"}; auto p = parser("()");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:2: unable to parse expression"); EXPECT_EQ(p->error(), "1:2: unable to parse expression");
} }
TEST_F(ParserImplTest, PrimaryExpression_ParenExpr_InvalidExpr) { TEST_F(ParserImplTest, PrimaryExpression_ParenExpr_InvalidExpr) {
ParserImpl p{"(if (a) {})"}; auto p = parser("(if (a) {})");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:2: unable to parse expression"); EXPECT_EQ(p->error(), "1:2: unable to parse expression");
} }
TEST_F(ParserImplTest, PrimaryExpression_Cast) { TEST_F(ParserImplTest, PrimaryExpression_Cast) {
auto tm = TypeManager::Instance(); auto f32_type = tm()->Get(std::make_unique<ast::type::F32Type>());
auto f32_type = tm->Get(std::make_unique<ast::type::F32Type>());
ParserImpl p{"cast<f32>(1)"}; auto p = parser("cast<f32>(1)");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsCast()); ASSERT_TRUE(e->IsCast());
@ -195,73 +193,70 @@ TEST_F(ParserImplTest, PrimaryExpression_Cast) {
ASSERT_TRUE(c->expr()->IsInitializer()); ASSERT_TRUE(c->expr()->IsInitializer());
ASSERT_TRUE(c->expr()->AsInitializer()->IsConstInitializer()); ASSERT_TRUE(c->expr()->AsInitializer()->IsConstInitializer());
TypeManager::Destroy();
} }
TEST_F(ParserImplTest, PrimaryExpression_Cast_MissingGreaterThan) { TEST_F(ParserImplTest, PrimaryExpression_Cast_MissingGreaterThan) {
ParserImpl p{"cast<f32(1)"}; auto p = parser("cast<f32(1)");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:9: missing > for cast expression"); EXPECT_EQ(p->error(), "1:9: missing > for cast expression");
} }
TEST_F(ParserImplTest, PrimaryExpression_Cast_MissingType) { TEST_F(ParserImplTest, PrimaryExpression_Cast_MissingType) {
ParserImpl p{"cast<>(1)"}; auto p = parser("cast<>(1)");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:6: missing type for cast expression"); EXPECT_EQ(p->error(), "1:6: missing type for cast expression");
} }
TEST_F(ParserImplTest, PrimaryExpression_Cast_InvalidType) { TEST_F(ParserImplTest, PrimaryExpression_Cast_InvalidType) {
ParserImpl p{"cast<invalid>(1)"}; auto p = parser("cast<invalid>(1)");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:6: unknown type alias 'invalid'"); EXPECT_EQ(p->error(), "1:6: unknown type alias 'invalid'");
} }
TEST_F(ParserImplTest, PrimaryExpression_Cast_MissingLeftParen) { TEST_F(ParserImplTest, PrimaryExpression_Cast_MissingLeftParen) {
ParserImpl p{"cast<f32>1)"}; auto p = parser("cast<f32>1)");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:10: expected ("); EXPECT_EQ(p->error(), "1:10: expected (");
} }
TEST_F(ParserImplTest, PrimaryExpression_Cast_MissingRightParen) { TEST_F(ParserImplTest, PrimaryExpression_Cast_MissingRightParen) {
ParserImpl p{"cast<f32>(1"}; auto p = parser("cast<f32>(1");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:12: expected )"); EXPECT_EQ(p->error(), "1:12: expected )");
} }
TEST_F(ParserImplTest, PrimaryExpression_Cast_MissingExpression) { TEST_F(ParserImplTest, PrimaryExpression_Cast_MissingExpression) {
ParserImpl p{"cast<f32>()"}; auto p = parser("cast<f32>()");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:11: unable to parse expression"); EXPECT_EQ(p->error(), "1:11: unable to parse expression");
} }
TEST_F(ParserImplTest, PrimaryExpression_Cast_InvalidExpression) { TEST_F(ParserImplTest, PrimaryExpression_Cast_InvalidExpression) {
ParserImpl p{"cast<f32>(if (a) {})"}; auto p = parser("cast<f32>(if (a) {})");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:11: unable to parse expression"); EXPECT_EQ(p->error(), "1:11: unable to parse expression");
} }
TEST_F(ParserImplTest, PrimaryExpression_As) { TEST_F(ParserImplTest, PrimaryExpression_As) {
auto tm = TypeManager::Instance(); auto f32_type = tm()->Get(std::make_unique<ast::type::F32Type>());
auto f32_type = tm->Get(std::make_unique<ast::type::F32Type>());
ParserImpl p{"as<f32>(1)"}; auto p = parser("as<f32>(1)");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsAs()); ASSERT_TRUE(e->IsAs());
@ -270,64 +265,62 @@ TEST_F(ParserImplTest, PrimaryExpression_As) {
ASSERT_TRUE(c->expr()->IsInitializer()); ASSERT_TRUE(c->expr()->IsInitializer());
ASSERT_TRUE(c->expr()->AsInitializer()->IsConstInitializer()); ASSERT_TRUE(c->expr()->AsInitializer()->IsConstInitializer());
TypeManager::Destroy();
} }
TEST_F(ParserImplTest, PrimaryExpression_As_MissingGreaterThan) { TEST_F(ParserImplTest, PrimaryExpression_As_MissingGreaterThan) {
ParserImpl p{"as<f32(1)"}; auto p = parser("as<f32(1)");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:7: missing > for as expression"); EXPECT_EQ(p->error(), "1:7: missing > for as expression");
} }
TEST_F(ParserImplTest, PrimaryExpression_As_MissingType) { TEST_F(ParserImplTest, PrimaryExpression_As_MissingType) {
ParserImpl p{"as<>(1)"}; auto p = parser("as<>(1)");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:4: missing type for as expression"); EXPECT_EQ(p->error(), "1:4: missing type for as expression");
} }
TEST_F(ParserImplTest, PrimaryExpression_As_InvalidType) { TEST_F(ParserImplTest, PrimaryExpression_As_InvalidType) {
ParserImpl p{"as<invalid>(1)"}; auto p = parser("as<invalid>(1)");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:4: unknown type alias 'invalid'"); EXPECT_EQ(p->error(), "1:4: unknown type alias 'invalid'");
} }
TEST_F(ParserImplTest, PrimaryExpression_As_MissingLeftParen) { TEST_F(ParserImplTest, PrimaryExpression_As_MissingLeftParen) {
ParserImpl p{"as<f32>1)"}; auto p = parser("as<f32>1)");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: expected ("); EXPECT_EQ(p->error(), "1:8: expected (");
} }
TEST_F(ParserImplTest, PrimaryExpression_As_MissingRightParen) { TEST_F(ParserImplTest, PrimaryExpression_As_MissingRightParen) {
ParserImpl p{"as<f32>(1"}; auto p = parser("as<f32>(1");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:10: expected )"); EXPECT_EQ(p->error(), "1:10: expected )");
} }
TEST_F(ParserImplTest, PrimaryExpression_As_MissingExpression) { TEST_F(ParserImplTest, PrimaryExpression_As_MissingExpression) {
ParserImpl p{"as<f32>()"}; auto p = parser("as<f32>()");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:9: unable to parse expression"); EXPECT_EQ(p->error(), "1:9: unable to parse expression");
} }
TEST_F(ParserImplTest, PrimaryExpression_As_InvalidExpression) { TEST_F(ParserImplTest, PrimaryExpression_As_InvalidExpression) {
ParserImpl p{"as<f32>(if (a) {})"}; auto p = parser("as<f32>(if (a) {})");
auto e = p.primary_expression(); auto e = p->primary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:9: unable to parse expression"); EXPECT_EQ(p->error(), "1:9: unable to parse expression");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -14,17 +14,16 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, RegardlessStmt) { TEST_F(ParserImplTest, RegardlessStmt) {
ParserImpl p{"regardless (a) { kill; }"}; auto p = parser("regardless (a) { kill; }");
auto e = p.regardless_stmt(); auto e = p->regardless_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRegardless()); ASSERT_TRUE(e->IsRegardless());
ASSERT_NE(e->condition(), nullptr); ASSERT_NE(e->condition(), nullptr);
@ -34,27 +33,27 @@ TEST_F(ParserImplTest, RegardlessStmt) {
} }
TEST_F(ParserImplTest, RegardlessStmt_InvalidCondition) { TEST_F(ParserImplTest, RegardlessStmt_InvalidCondition) {
ParserImpl p{"regardless(if(a){}) {}"}; auto p = parser("regardless(if(a){}) {}");
auto e = p.regardless_stmt(); auto e = p->regardless_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:12: unable to parse expression"); EXPECT_EQ(p->error(), "1:12: unable to parse expression");
} }
TEST_F(ParserImplTest, RegardlessStmt_EmptyCondition) { TEST_F(ParserImplTest, RegardlessStmt_EmptyCondition) {
ParserImpl p{"regardless() {}"}; auto p = parser("regardless() {}");
auto e = p.regardless_stmt(); auto e = p->regardless_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:12: unable to parse expression"); EXPECT_EQ(p->error(), "1:12: unable to parse expression");
} }
TEST_F(ParserImplTest, RegardlessStmt_InvalidBody) { TEST_F(ParserImplTest, RegardlessStmt_InvalidBody) {
ParserImpl p{"regardless(a + 2 - 5 == true) { kill }"}; auto p = parser("regardless(a + 2 - 5 == true) { kill }");
auto e = p.regardless_stmt(); auto e = p->regardless_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:38: missing ;"); EXPECT_EQ(p->error(), "1:38: missing ;");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -18,17 +18,16 @@
#include "src/ast/identifier_expression.h" #include "src/ast/identifier_expression.h"
#include "src/ast/relational_expression.h" #include "src/ast/relational_expression.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, RelationalExpression_Parses_LessThan) { TEST_F(ParserImplTest, RelationalExpression_Parses_LessThan) {
ParserImpl p{"a < true"}; auto p = parser("a < true");
auto e = p.relational_expression(); auto e = p->relational_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRelational()); ASSERT_TRUE(e->IsRelational());
@ -48,9 +47,9 @@ TEST_F(ParserImplTest, RelationalExpression_Parses_LessThan) {
} }
TEST_F(ParserImplTest, RelationalExpression_Parses_GreaterThan) { TEST_F(ParserImplTest, RelationalExpression_Parses_GreaterThan) {
ParserImpl p{"a > true"}; auto p = parser("a > true");
auto e = p.relational_expression(); auto e = p->relational_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRelational()); ASSERT_TRUE(e->IsRelational());
@ -70,9 +69,9 @@ TEST_F(ParserImplTest, RelationalExpression_Parses_GreaterThan) {
} }
TEST_F(ParserImplTest, RelationalExpression_Parses_LessThanEqual) { TEST_F(ParserImplTest, RelationalExpression_Parses_LessThanEqual) {
ParserImpl p{"a <= true"}; auto p = parser("a <= true");
auto e = p.relational_expression(); auto e = p->relational_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRelational()); ASSERT_TRUE(e->IsRelational());
@ -92,9 +91,9 @@ TEST_F(ParserImplTest, RelationalExpression_Parses_LessThanEqual) {
} }
TEST_F(ParserImplTest, RelationalExpression_Parses_GreaterThanEqual) { TEST_F(ParserImplTest, RelationalExpression_Parses_GreaterThanEqual) {
ParserImpl p{"a >= true"}; auto p = parser("a >= true");
auto e = p.relational_expression(); auto e = p->relational_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRelational()); ASSERT_TRUE(e->IsRelational());
@ -114,24 +113,24 @@ TEST_F(ParserImplTest, RelationalExpression_Parses_GreaterThanEqual) {
} }
TEST_F(ParserImplTest, RelationalExpression_InvalidLHS) { TEST_F(ParserImplTest, RelationalExpression_InvalidLHS) {
ParserImpl p{"if (a) {} < true"}; auto p = parser("if (a) {} < true");
auto e = p.relational_expression(); auto e = p->relational_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
} }
TEST_F(ParserImplTest, RelationalExpression_InvalidRHS) { TEST_F(ParserImplTest, RelationalExpression_InvalidRHS) {
ParserImpl p{"true < if (a) {}"}; auto p = parser("true < if (a) {}");
auto e = p.relational_expression(); auto e = p->relational_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: unable to parse right side of < expression"); EXPECT_EQ(p->error(), "1:8: unable to parse right side of < expression");
} }
TEST_F(ParserImplTest, RelationalExpression_NoOr_ReturnsLHS) { TEST_F(ParserImplTest, RelationalExpression_NoOr_ReturnsLHS) {
ParserImpl p{"a true"}; auto p = parser("a true");
auto e = p.relational_expression(); auto e = p->relational_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsIdentifier()); ASSERT_TRUE(e->IsIdentifier());
} }

View File

@ -18,17 +18,16 @@
#include "src/ast/identifier_expression.h" #include "src/ast/identifier_expression.h"
#include "src/ast/relational_expression.h" #include "src/ast/relational_expression.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftLeft) { TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftLeft) {
ParserImpl p{"a << true"}; auto p = parser("a << true");
auto e = p.shift_expression(); auto e = p->shift_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRelational()); ASSERT_TRUE(e->IsRelational());
@ -48,9 +47,9 @@ TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftLeft) {
} }
TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftRight) { TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftRight) {
ParserImpl p{"a >> true"}; auto p = parser("a >> true");
auto e = p.shift_expression(); auto e = p->shift_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRelational()); ASSERT_TRUE(e->IsRelational());
@ -70,9 +69,9 @@ TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftRight) {
} }
TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftRightArith) { TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftRightArith) {
ParserImpl p{"a >>> true"}; auto p = parser("a >>> true");
auto e = p.shift_expression(); auto e = p->shift_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRelational()); ASSERT_TRUE(e->IsRelational());
@ -92,24 +91,24 @@ TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftRightArith) {
} }
TEST_F(ParserImplTest, ShiftExpression_InvalidLHS) { TEST_F(ParserImplTest, ShiftExpression_InvalidLHS) {
ParserImpl p{"if (a) {} << true"}; auto p = parser("if (a) {} << true");
auto e = p.shift_expression(); auto e = p->shift_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
} }
TEST_F(ParserImplTest, ShiftExpression_InvalidRHS) { TEST_F(ParserImplTest, ShiftExpression_InvalidRHS) {
ParserImpl p{"true << if (a) {}"}; auto p = parser("true << if (a) {}");
auto e = p.shift_expression(); auto e = p->shift_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:9: unable to parse right side of << expression"); EXPECT_EQ(p->error(), "1:9: unable to parse right side of << expression");
} }
TEST_F(ParserImplTest, ShiftExpression_NoOr_ReturnsLHS) { TEST_F(ParserImplTest, ShiftExpression_NoOr_ReturnsLHS) {
ParserImpl p{"a true"}; auto p = parser("a true");
auto e = p.shift_expression(); auto e = p->shift_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsIdentifier()); ASSERT_TRUE(e->IsIdentifier());
} }

View File

@ -16,32 +16,31 @@
#include "src/ast/return_statement.h" #include "src/ast/return_statement.h"
#include "src/ast/statement.h" #include "src/ast/statement.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, Statement) { TEST_F(ParserImplTest, Statement) {
ParserImpl p{"return;"}; auto p = parser("return;");
auto e = p.statement(); auto e = p->statement();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
EXPECT_TRUE(e->IsReturn()); EXPECT_TRUE(e->IsReturn());
} }
TEST_F(ParserImplTest, Statement_Semicolon) { TEST_F(ParserImplTest, Statement_Semicolon) {
ParserImpl p{";"}; auto p = parser(";");
auto e = p.statement(); auto e = p->statement();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
} }
TEST_F(ParserImplTest, Statement_Return_NoValue) { TEST_F(ParserImplTest, Statement_Return_NoValue) {
ParserImpl p{"return;"}; auto p = parser("return;");
auto e = p.statement(); auto e = p->statement();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsReturn()); ASSERT_TRUE(e->IsReturn());
@ -50,9 +49,9 @@ TEST_F(ParserImplTest, Statement_Return_NoValue) {
} }
TEST_F(ParserImplTest, Statement_Return_Value) { TEST_F(ParserImplTest, Statement_Return_Value) {
ParserImpl p{"return a + b * (.1 - .2);"}; auto p = parser("return a + b * (.1 - .2);");
auto e = p.statement(); auto e = p->statement();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsReturn()); ASSERT_TRUE(e->IsReturn());
@ -62,227 +61,227 @@ TEST_F(ParserImplTest, Statement_Return_Value) {
} }
TEST_F(ParserImplTest, Statement_Return_MissingSemi) { TEST_F(ParserImplTest, Statement_Return_MissingSemi) {
ParserImpl p{"return"}; auto p = parser("return");
auto e = p.statement(); auto e = p->statement();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:7: missing ;"); EXPECT_EQ(p->error(), "1:7: missing ;");
} }
TEST_F(ParserImplTest, Statement_Return_Invalid) { TEST_F(ParserImplTest, Statement_Return_Invalid) {
ParserImpl p{"return if(a) {};"}; auto p = parser("return if(a) {};");
auto e = p.statement(); auto e = p->statement();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: missing ;"); EXPECT_EQ(p->error(), "1:8: missing ;");
} }
TEST_F(ParserImplTest, Statement_If) { TEST_F(ParserImplTest, Statement_If) {
ParserImpl p{"if (a) {}"}; auto p = parser("if (a) {}");
auto e = p.statement(); auto e = p->statement();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsIf()); ASSERT_TRUE(e->IsIf());
} }
TEST_F(ParserImplTest, Statement_If_Invalid) { TEST_F(ParserImplTest, Statement_If_Invalid) {
ParserImpl p{"if (a) { fn main() -> {}}"}; auto p = parser("if (a) { fn main() -> {}}");
auto e = p.statement(); auto e = p->statement();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:10: missing }"); EXPECT_EQ(p->error(), "1:10: missing }");
} }
TEST_F(ParserImplTest, Statement_Unless) { TEST_F(ParserImplTest, Statement_Unless) {
ParserImpl p{"unless (a) {}"}; auto p = parser("unless (a) {}");
auto e = p.statement(); auto e = p->statement();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnless()); ASSERT_TRUE(e->IsUnless());
} }
TEST_F(ParserImplTest, Statement_Unless_Invalid) { TEST_F(ParserImplTest, Statement_Unless_Invalid) {
ParserImpl p{"unless () {}"}; auto p = parser("unless () {}");
auto e = p.statement(); auto e = p->statement();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:9: unable to parse expression"); EXPECT_EQ(p->error(), "1:9: unable to parse expression");
} }
TEST_F(ParserImplTest, Statement_Regardless) { TEST_F(ParserImplTest, Statement_Regardless) {
ParserImpl p{"regardless (a) {}"}; auto p = parser("regardless (a) {}");
auto e = p.statement(); auto e = p->statement();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRegardless()); ASSERT_TRUE(e->IsRegardless());
} }
TEST_F(ParserImplTest, Statement_Regardless_Invalid) { TEST_F(ParserImplTest, Statement_Regardless_Invalid) {
ParserImpl p{"regardless () {}"}; auto p = parser("regardless () {}");
auto e = p.statement(); auto e = p->statement();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:13: unable to parse expression"); EXPECT_EQ(p->error(), "1:13: unable to parse expression");
} }
TEST_F(ParserImplTest, Statement_Variable) { TEST_F(ParserImplTest, Statement_Variable) {
ParserImpl p{"var a : i32 = 1;"}; auto p = parser("var a : i32 = 1;");
auto e = p.statement(); auto e = p->statement();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsVariable()); ASSERT_TRUE(e->IsVariable());
} }
TEST_F(ParserImplTest, Statement_Variable_Invalid) { TEST_F(ParserImplTest, Statement_Variable_Invalid) {
ParserImpl p{"var a : i32 =;"}; auto p = parser("var a : i32 =;");
auto e = p.statement(); auto e = p->statement();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:14: missing initializer for variable declaration"); EXPECT_EQ(p->error(), "1:14: missing initializer for variable declaration");
} }
TEST_F(ParserImplTest, Statement_Variable_MissingSemicolon) { TEST_F(ParserImplTest, Statement_Variable_MissingSemicolon) {
ParserImpl p{"var a : i32"}; auto p = parser("var a : i32");
auto e = p.statement(); auto e = p->statement();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:12: missing ;"); EXPECT_EQ(p->error(), "1:12: missing ;");
} }
TEST_F(ParserImplTest, Statement_Switch) { TEST_F(ParserImplTest, Statement_Switch) {
ParserImpl p{"switch (a) {}"}; auto p = parser("switch (a) {}");
auto e = p.statement(); auto e = p->statement();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsSwitch()); ASSERT_TRUE(e->IsSwitch());
} }
TEST_F(ParserImplTest, Statement_Switch_Invalid) { TEST_F(ParserImplTest, Statement_Switch_Invalid) {
ParserImpl p{"switch (a) { case: {}}"}; auto p = parser("switch (a) { case: {}}");
auto e = p.statement(); auto e = p->statement();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:18: unable to parse case conditional"); EXPECT_EQ(p->error(), "1:18: unable to parse case conditional");
} }
TEST_F(ParserImplTest, Statement_Loop) { TEST_F(ParserImplTest, Statement_Loop) {
ParserImpl p{"loop {}"}; auto p = parser("loop {}");
auto e = p.statement(); auto e = p->statement();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsLoop()); ASSERT_TRUE(e->IsLoop());
} }
TEST_F(ParserImplTest, Statement_Loop_Invalid) { TEST_F(ParserImplTest, Statement_Loop_Invalid) {
ParserImpl p{"loop kill; }"}; auto p = parser("loop kill; }");
auto e = p.statement(); auto e = p->statement();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:6: missing { for loop"); EXPECT_EQ(p->error(), "1:6: missing { for loop");
} }
TEST_F(ParserImplTest, Statement_Assignment) { TEST_F(ParserImplTest, Statement_Assignment) {
ParserImpl p{"a = b;"}; auto p = parser("a = b;");
auto e = p.statement(); auto e = p->statement();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
EXPECT_TRUE(e->IsAssign()); EXPECT_TRUE(e->IsAssign());
} }
TEST_F(ParserImplTest, Statement_Assignment_Invalid) { TEST_F(ParserImplTest, Statement_Assignment_Invalid) {
ParserImpl p{"a = if(b) {};"}; auto p = parser("a = if(b) {};");
auto e = p.statement(); auto e = p->statement();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:5: unable to parse right side of assignment"); EXPECT_EQ(p->error(), "1:5: unable to parse right side of assignment");
} }
TEST_F(ParserImplTest, Statement_Assignment_MissingSemicolon) { TEST_F(ParserImplTest, Statement_Assignment_MissingSemicolon) {
ParserImpl p{"a = b"}; auto p = parser("a = b");
auto e = p.statement(); auto e = p->statement();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:6: missing ;"); EXPECT_EQ(p->error(), "1:6: missing ;");
} }
TEST_F(ParserImplTest, Statement_Break) { TEST_F(ParserImplTest, Statement_Break) {
ParserImpl p{"break;"}; auto p = parser("break;");
auto e = p.statement(); auto e = p->statement();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
EXPECT_TRUE(e->IsBreak()); EXPECT_TRUE(e->IsBreak());
} }
TEST_F(ParserImplTest, Statement_Break_Invalid) { TEST_F(ParserImplTest, Statement_Break_Invalid) {
ParserImpl p{"break if (a = b);"}; auto p = parser("break if (a = b);");
auto e = p.statement(); auto e = p->statement();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:13: expected )"); EXPECT_EQ(p->error(), "1:13: expected )");
} }
TEST_F(ParserImplTest, Statement_Break_MissingSemicolon) { TEST_F(ParserImplTest, Statement_Break_MissingSemicolon) {
ParserImpl p{"break if (a == b)"}; auto p = parser("break if (a == b)");
auto e = p.statement(); auto e = p->statement();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:18: missing ;"); EXPECT_EQ(p->error(), "1:18: missing ;");
} }
TEST_F(ParserImplTest, Statement_Continue) { TEST_F(ParserImplTest, Statement_Continue) {
ParserImpl p{"continue;"}; auto p = parser("continue;");
auto e = p.statement(); auto e = p->statement();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
EXPECT_TRUE(e->IsContinue()); EXPECT_TRUE(e->IsContinue());
} }
TEST_F(ParserImplTest, Statement_Continue_Invalid) { TEST_F(ParserImplTest, Statement_Continue_Invalid) {
ParserImpl p{"continue if (a = b);"}; auto p = parser("continue if (a = b);");
auto e = p.statement(); auto e = p->statement();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:16: expected )"); EXPECT_EQ(p->error(), "1:16: expected )");
} }
TEST_F(ParserImplTest, Statement_Continue_MissingSemicolon) { TEST_F(ParserImplTest, Statement_Continue_MissingSemicolon) {
ParserImpl p{"continue if (a == b)"}; auto p = parser("continue if (a == b)");
auto e = p.statement(); auto e = p->statement();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:21: missing ;"); EXPECT_EQ(p->error(), "1:21: missing ;");
} }
TEST_F(ParserImplTest, Statement_Kill) { TEST_F(ParserImplTest, Statement_Kill) {
ParserImpl p{"kill;"}; auto p = parser("kill;");
auto e = p.statement(); auto e = p->statement();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_NE(e, nullptr); EXPECT_NE(e, nullptr);
ASSERT_TRUE(e->IsKill()); ASSERT_TRUE(e->IsKill());
} }
TEST_F(ParserImplTest, Statement_Kill_MissingSemicolon) { TEST_F(ParserImplTest, Statement_Kill_MissingSemicolon) {
ParserImpl p{"kill"}; auto p = parser("kill");
auto e = p.statement(); auto e = p->statement();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(e, nullptr); EXPECT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:5: missing ;"); EXPECT_EQ(p->error(), "1:5: missing ;");
} }
TEST_F(ParserImplTest, Statement_Nop) { TEST_F(ParserImplTest, Statement_Nop) {
ParserImpl p{"nop;"}; auto p = parser("nop;");
auto e = p.statement(); auto e = p->statement();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_NE(e, nullptr); EXPECT_NE(e, nullptr);
ASSERT_TRUE(e->IsNop()); ASSERT_TRUE(e->IsNop());
} }
TEST_F(ParserImplTest, Statement_Nop_MissingSemicolon) { TEST_F(ParserImplTest, Statement_Nop_MissingSemicolon) {
ParserImpl p{"nop"}; auto p = parser("nop");
auto e = p.statement(); auto e = p->statement();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(e, nullptr); EXPECT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:4: missing ;"); EXPECT_EQ(p->error(), "1:4: missing ;");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -15,17 +15,16 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/ast/statement.h" #include "src/ast/statement.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, Statements) { TEST_F(ParserImplTest, Statements) {
ParserImpl p{"nop; kill; return;"}; auto p = parser("nop; kill; return;");
auto e = p.statements(); auto e = p->statements();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e.size(), 3); ASSERT_EQ(e.size(), 3);
EXPECT_TRUE(e[0]->IsNop()); EXPECT_TRUE(e[0]->IsNop());
EXPECT_TRUE(e[1]->IsKill()); EXPECT_TRUE(e[1]->IsKill());
@ -33,9 +32,9 @@ TEST_F(ParserImplTest, Statements) {
} }
TEST_F(ParserImplTest, Statements_Empty) { TEST_F(ParserImplTest, Statements_Empty) {
ParserImpl p{""}; auto p = parser("");
auto e = p.statements(); auto e = p->statements();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e.size(), 0); ASSERT_EQ(e.size(), 0);
} }

View File

@ -15,12 +15,12 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/ast/storage_class.h" #include "src/ast/storage_class.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
namespace {
using ParserImplTest = testing::Test;
struct StorageClassData { struct StorageClassData {
const char* input; const char* input;
@ -30,16 +30,41 @@ inline std::ostream& operator<<(std::ostream& out, StorageClassData data) {
out << std::string(data.input); out << std::string(data.input);
return out; return out;
} }
using StorageClassTest = testing::TestWithParam<StorageClassData>;
class StorageClassTest : public testing::TestWithParam<StorageClassData> {
public:
StorageClassTest() = default;
~StorageClassTest() = default;
void SetUp() { ctx_.type_mgr = &tm_; }
void TearDown() {
impl_ = nullptr;
ctx_.type_mgr = nullptr;
}
ParserImpl* parser(const std::string& str) {
impl_ = std::make_unique<ParserImpl>(ctx_, str);
return impl_.get();
}
private:
std::unique_ptr<ParserImpl> impl_;
Context ctx_;
TypeManager tm_;
};
} // namespace
TEST_P(StorageClassTest, Parses) { TEST_P(StorageClassTest, Parses) {
auto params = GetParam(); auto params = GetParam();
ParserImpl p{params.input}; auto p = parser(params.input);
auto sc = p.storage_class(); auto sc = p->storage_class();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
EXPECT_EQ(sc, params.result); EXPECT_EQ(sc, params.result);
auto t = p.next(); auto t = p->next();
EXPECT_TRUE(t.IsEof()); EXPECT_TRUE(t.IsEof());
} }
INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P(
@ -59,11 +84,11 @@ INSTANTIATE_TEST_SUITE_P(
StorageClassData{"function", ast::StorageClass::kFunction})); StorageClassData{"function", ast::StorageClass::kFunction}));
TEST_F(ParserImplTest, StorageClass_NoMatch) { TEST_F(ParserImplTest, StorageClass_NoMatch) {
ParserImpl p{"not-a-storage-class"}; auto p = parser("not-a-storage-class");
auto sc = p.storage_class(); auto sc = p->storage_class();
ASSERT_EQ(sc, ast::StorageClass::kNone); ASSERT_EQ(sc, ast::StorageClass::kNone);
auto t = p.next(); auto t = p->next();
EXPECT_TRUE(t.IsIdentifier()); EXPECT_TRUE(t.IsIdentifier());
EXPECT_EQ(t.to_str(), "not"); EXPECT_EQ(t.to_str(), "not");
} }

View File

@ -15,64 +15,60 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/ast/type/i32_type.h" #include "src/ast/type/i32_type.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
#include "src/type_manager.h" #include "src/type_manager.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, StructBodyDecl_Parses) { TEST_F(ParserImplTest, StructBodyDecl_Parses) {
auto i32 = auto i32 = tm()->Get(std::make_unique<ast::type::I32Type>());
TypeManager::Instance()->Get(std::make_unique<ast::type::I32Type>());
ParserImpl p{"{a : i32;}"}; auto p = parser("{a : i32;}");
auto m = p.struct_body_decl(); auto m = p->struct_body_decl();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_EQ(m.size(), 1); ASSERT_EQ(m.size(), 1);
const auto& mem = m[0]; const auto& mem = m[0];
EXPECT_EQ(mem->name(), "a"); EXPECT_EQ(mem->name(), "a");
EXPECT_EQ(mem->type(), i32); EXPECT_EQ(mem->type(), i32);
EXPECT_EQ(mem->decorations().size(), 0); EXPECT_EQ(mem->decorations().size(), 0);
TypeManager::Destroy();
} }
TEST_F(ParserImplTest, StructBodyDecl_ParsesEmpty) { TEST_F(ParserImplTest, StructBodyDecl_ParsesEmpty) {
ParserImpl p{"{}"}; auto p = parser("{}");
auto m = p.struct_body_decl(); auto m = p->struct_body_decl();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_EQ(m.size(), 0); ASSERT_EQ(m.size(), 0);
} }
TEST_F(ParserImplTest, StructBodyDecl_InvalidMember) { TEST_F(ParserImplTest, StructBodyDecl_InvalidMember) {
ParserImpl p{R"( auto p = parser(R"(
{ {
[[offset nan]] a : i32; [[offset nan]] a : i32;
})"}; })");
auto m = p.struct_body_decl(); auto m = p->struct_body_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "3:12: invalid value for offset decoration"); EXPECT_EQ(p->error(), "3:12: invalid value for offset decoration");
} }
TEST_F(ParserImplTest, StructBodyDecl_MissingClosingBracket) { TEST_F(ParserImplTest, StructBodyDecl_MissingClosingBracket) {
ParserImpl p{"{a : i32;"}; auto p = parser("{a : i32;");
auto m = p.struct_body_decl(); auto m = p->struct_body_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:10: missing } for struct declaration"); EXPECT_EQ(p->error(), "1:10: missing } for struct declaration");
} }
TEST_F(ParserImplTest, StructBodyDecl_InvalidToken) { TEST_F(ParserImplTest, StructBodyDecl_InvalidToken) {
ParserImpl p{R"( auto p = parser(R"(
{ {
a : i32; a : i32;
1.23 1.23
} )"}; } )");
auto m = p.struct_body_decl(); auto m = p->struct_body_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "4:3: invalid identifier declaration"); EXPECT_EQ(p->error(), "4:3: invalid identifier declaration");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -15,21 +15,20 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/ast/type/struct_type.h" #include "src/ast/type/struct_type.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, StructDecl_Parses) { TEST_F(ParserImplTest, StructDecl_Parses) {
ParserImpl p{R"( auto p = parser(R"(
struct { struct {
a : i32; a : i32;
[[offset 4 ]] b : f32; [[offset 4 ]] b : f32;
})"}; })");
auto s = p.struct_decl(); auto s = p->struct_decl();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_NE(s, nullptr); ASSERT_NE(s, nullptr);
ASSERT_EQ(s->impl()->members().size(), 2); ASSERT_EQ(s->impl()->members().size(), 2);
EXPECT_EQ(s->impl()->members()[0]->name(), "a"); EXPECT_EQ(s->impl()->members()[0]->name(), "a");
@ -37,13 +36,13 @@ struct {
} }
TEST_F(ParserImplTest, StructDecl_ParsesWithDecoration) { TEST_F(ParserImplTest, StructDecl_ParsesWithDecoration) {
ParserImpl p{R"( auto p = parser(R"(
[[block]] struct { [[block]] struct {
a : f32; a : f32;
b : f32; b : f32;
})"}; })");
auto s = p.struct_decl(); auto s = p->struct_decl();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_NE(s, nullptr); ASSERT_NE(s, nullptr);
ASSERT_EQ(s->impl()->members().size(), 2); ASSERT_EQ(s->impl()->members().size(), 2);
EXPECT_EQ(s->impl()->members()[0]->name(), "a"); EXPECT_EQ(s->impl()->members()[0]->name(), "a");
@ -51,43 +50,43 @@ TEST_F(ParserImplTest, StructDecl_ParsesWithDecoration) {
} }
TEST_F(ParserImplTest, StructDecl_EmptyMembers) { TEST_F(ParserImplTest, StructDecl_EmptyMembers) {
ParserImpl p{"struct {}"}; auto p = parser("struct {}");
auto s = p.struct_decl(); auto s = p->struct_decl();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_NE(s, nullptr); ASSERT_NE(s, nullptr);
ASSERT_EQ(s->impl()->members().size(), 0); ASSERT_EQ(s->impl()->members().size(), 0);
} }
TEST_F(ParserImplTest, StructDecl_MissingBracketLeft) { TEST_F(ParserImplTest, StructDecl_MissingBracketLeft) {
ParserImpl p{"struct }"}; auto p = parser("struct }");
auto s = p.struct_decl(); auto s = p->struct_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(s, nullptr); ASSERT_EQ(s, nullptr);
EXPECT_EQ(p.error(), "1:8: missing { for struct declaration"); EXPECT_EQ(p->error(), "1:8: missing { for struct declaration");
} }
TEST_F(ParserImplTest, StructDecl_InvalidStructBody) { TEST_F(ParserImplTest, StructDecl_InvalidStructBody) {
ParserImpl p{"struct { a : B; }"}; auto p = parser("struct { a : B; }");
auto s = p.struct_decl(); auto s = p->struct_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(s, nullptr); ASSERT_EQ(s, nullptr);
EXPECT_EQ(p.error(), "1:14: unknown type alias 'B'"); EXPECT_EQ(p->error(), "1:14: unknown type alias 'B'");
} }
TEST_F(ParserImplTest, StructDecl_InvalidStructDecorationDecl) { TEST_F(ParserImplTest, StructDecl_InvalidStructDecorationDecl) {
ParserImpl p{"[[block struct { a : i32; }"}; auto p = parser("[[block struct { a : i32; }");
auto s = p.struct_decl(); auto s = p->struct_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(s, nullptr); ASSERT_EQ(s, nullptr);
EXPECT_EQ(p.error(), "1:9: missing ]] for struct decoration"); EXPECT_EQ(p->error(), "1:9: missing ]] for struct decoration");
} }
TEST_F(ParserImplTest, StructDecl_MissingStruct) { TEST_F(ParserImplTest, StructDecl_MissingStruct) {
ParserImpl p{"[[block]] {}"}; auto p = parser("[[block]] {}");
auto s = p.struct_decl(); auto s = p->struct_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(s, nullptr); ASSERT_EQ(s, nullptr);
EXPECT_EQ(p.error(), "1:11: missing struct declaration"); EXPECT_EQ(p->error(), "1:11: missing struct declaration");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -14,32 +14,31 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, StructDecorationDecl_Parses) { TEST_F(ParserImplTest, StructDecorationDecl_Parses) {
ParserImpl p{"[[block]]"}; auto p = parser("[[block]]");
auto d = p.struct_decoration_decl(); auto d = p->struct_decoration_decl();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
EXPECT_EQ(d, ast::StructDecoration::kBlock); EXPECT_EQ(d, ast::StructDecoration::kBlock);
} }
TEST_F(ParserImplTest, StructDecorationDecl_MissingAttrRight) { TEST_F(ParserImplTest, StructDecorationDecl_MissingAttrRight) {
ParserImpl p{"[[block"}; auto p = parser("[[block");
p.struct_decoration_decl(); p->struct_decoration_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:8: missing ]] for struct decoration"); EXPECT_EQ(p->error(), "1:8: missing ]] for struct decoration");
} }
TEST_F(ParserImplTest, StructDecorationDecl_InvalidDecoration) { TEST_F(ParserImplTest, StructDecorationDecl_InvalidDecoration) {
ParserImpl p{"[[invalid]]"}; auto p = parser("[[invalid]]");
p.struct_decoration_decl(); p->struct_decoration_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:3: unknown struct decoration"); EXPECT_EQ(p->error(), "1:3: unknown struct decoration");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -15,12 +15,12 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/ast/struct_decoration.h" #include "src/ast/struct_decoration.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
namespace {
using ParserImplTest = testing::Test;
struct StructDecorationData { struct StructDecorationData {
const char* input; const char* input;
@ -30,16 +30,42 @@ inline std::ostream& operator<<(std::ostream& out, StructDecorationData data) {
out << std::string(data.input); out << std::string(data.input);
return out; return out;
} }
using StructDecorationTest = testing::TestWithParam<StructDecorationData>;
class StructDecorationTest
: public testing::TestWithParam<StructDecorationData> {
public:
StructDecorationTest() = default;
~StructDecorationTest() = default;
void SetUp() { ctx_.type_mgr = &tm_; }
void TearDown() {
impl_ = nullptr;
ctx_.type_mgr = nullptr;
}
ParserImpl* parser(const std::string& str) {
impl_ = std::make_unique<ParserImpl>(ctx_, str);
return impl_.get();
}
private:
std::unique_ptr<ParserImpl> impl_;
Context ctx_;
TypeManager tm_;
};
} // namespace
TEST_P(StructDecorationTest, Parses) { TEST_P(StructDecorationTest, Parses) {
auto params = GetParam(); auto params = GetParam();
ParserImpl p{params.input}; auto p = parser(params.input);
auto deco = p.struct_decoration(); auto deco = p->struct_decoration();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
EXPECT_EQ(deco, params.result); EXPECT_EQ(deco, params.result);
auto t = p.next(); auto t = p->next();
EXPECT_TRUE(t.IsEof()); EXPECT_TRUE(t.IsEof());
} }
INSTANTIATE_TEST_SUITE_P(ParserImplTest, INSTANTIATE_TEST_SUITE_P(ParserImplTest,
@ -48,11 +74,11 @@ INSTANTIATE_TEST_SUITE_P(ParserImplTest,
"block", ast::StructDecoration::kBlock})); "block", ast::StructDecoration::kBlock}));
TEST_F(ParserImplTest, StructDecoration_NoMatch) { TEST_F(ParserImplTest, StructDecoration_NoMatch) {
ParserImpl p{"not-a-stage"}; auto p = parser("not-a-stage");
auto deco = p.struct_decoration(); auto deco = p->struct_decoration();
ASSERT_EQ(deco, ast::StructDecoration::kNone); ASSERT_EQ(deco, ast::StructDecoration::kNone);
auto t = p.next(); auto t = p->next();
EXPECT_TRUE(t.IsIdentifier()); EXPECT_TRUE(t.IsIdentifier());
EXPECT_EQ(t.to_str(), "not"); EXPECT_EQ(t.to_str(), "not");
} }

View File

@ -15,54 +15,53 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/ast/struct_member_offset_decoration.h" #include "src/ast/struct_member_offset_decoration.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, StructMemberDecorationDecl_EmptyStr) { TEST_F(ParserImplTest, StructMemberDecorationDecl_EmptyStr) {
ParserImpl p{""}; auto p = parser("");
auto deco = p.struct_member_decoration_decl(); auto deco = p->struct_member_decoration_decl();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
EXPECT_EQ(deco.size(), 0); EXPECT_EQ(deco.size(), 0);
} }
TEST_F(ParserImplTest, StructMemberDecorationDecl_EmptyBlock) { TEST_F(ParserImplTest, StructMemberDecorationDecl_EmptyBlock) {
ParserImpl p{"[[]]"}; auto p = parser("[[]]");
auto deco = p.struct_member_decoration_decl(); auto deco = p->struct_member_decoration_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:3: empty struct member decoration found"); EXPECT_EQ(p->error(), "1:3: empty struct member decoration found");
} }
TEST_F(ParserImplTest, StructMemberDecorationDecl_Single) { TEST_F(ParserImplTest, StructMemberDecorationDecl_Single) {
ParserImpl p{"[[offset 4]]"}; auto p = parser("[[offset 4]]");
auto deco = p.struct_member_decoration_decl(); auto deco = p->struct_member_decoration_decl();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_EQ(deco.size(), 1); ASSERT_EQ(deco.size(), 1);
EXPECT_TRUE(deco[0]->IsOffset()); EXPECT_TRUE(deco[0]->IsOffset());
} }
TEST_F(ParserImplTest, StructMemberDecorationDecl_HandlesDuplicate) { TEST_F(ParserImplTest, StructMemberDecorationDecl_HandlesDuplicate) {
ParserImpl p{"[[offset 2, offset 4]]"}; auto p = parser("[[offset 2, offset 4]]");
auto deco = p.struct_member_decoration_decl(); auto deco = p->struct_member_decoration_decl();
ASSERT_TRUE(p.has_error()) << p.error(); ASSERT_TRUE(p->has_error()) << p->error();
EXPECT_EQ(p.error(), "1:21: duplicate offset decoration found"); EXPECT_EQ(p->error(), "1:21: duplicate offset decoration found");
} }
TEST_F(ParserImplTest, StructMemberDecorationDecl_InvalidDecoration) { TEST_F(ParserImplTest, StructMemberDecorationDecl_InvalidDecoration) {
ParserImpl p{"[[offset nan]]"}; auto p = parser("[[offset nan]]");
auto deco = p.struct_member_decoration_decl(); auto deco = p->struct_member_decoration_decl();
ASSERT_TRUE(p.has_error()) << p.error(); ASSERT_TRUE(p->has_error()) << p->error();
EXPECT_EQ(p.error(), "1:10: invalid value for offset decoration"); EXPECT_EQ(p->error(), "1:10: invalid value for offset decoration");
} }
TEST_F(ParserImplTest, StructMemberDecorationDecl_MissingClose) { TEST_F(ParserImplTest, StructMemberDecorationDecl_MissingClose) {
ParserImpl p{"[[offset 4"}; auto p = parser("[[offset 4");
auto deco = p.struct_member_decoration_decl(); auto deco = p->struct_member_decoration_decl();
ASSERT_TRUE(p.has_error()) << p.error(); ASSERT_TRUE(p->has_error()) << p->error();
EXPECT_EQ(p.error(), "1:11: missing ]] for struct member decoration"); EXPECT_EQ(p->error(), "1:11: missing ]] for struct member decoration");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -15,18 +15,17 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/ast/struct_member_offset_decoration.h" #include "src/ast/struct_member_offset_decoration.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, StructMemberDecoration_Offset) { TEST_F(ParserImplTest, StructMemberDecoration_Offset) {
ParserImpl p{"offset 4"}; auto p = parser("offset 4");
auto deco = p.struct_member_decoration(); auto deco = p->struct_member_decoration();
ASSERT_NE(deco, nullptr); ASSERT_NE(deco, nullptr);
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_TRUE(deco->IsOffset()); ASSERT_TRUE(deco->IsOffset());
auto o = deco->AsOffset(); auto o = deco->AsOffset();
@ -34,19 +33,19 @@ TEST_F(ParserImplTest, StructMemberDecoration_Offset) {
} }
TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingValue) { TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingValue) {
ParserImpl p{"offset"}; auto p = parser("offset");
auto deco = p.struct_member_decoration(); auto deco = p->struct_member_decoration();
ASSERT_EQ(deco, nullptr); ASSERT_EQ(deco, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:7: invalid value for offset decoration"); EXPECT_EQ(p->error(), "1:7: invalid value for offset decoration");
} }
TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingInvalid) { TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingInvalid) {
ParserImpl p{"offset nan"}; auto p = parser("offset nan");
auto deco = p.struct_member_decoration(); auto deco = p->struct_member_decoration();
ASSERT_EQ(deco, nullptr); ASSERT_EQ(deco, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:8: invalid value for offset decoration"); EXPECT_EQ(p->error(), "1:8: invalid value for offset decoration");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -16,37 +16,32 @@
#include "src/ast/struct_member_offset_decoration.h" #include "src/ast/struct_member_offset_decoration.h"
#include "src/ast/type/i32_type.h" #include "src/ast/type/i32_type.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
#include "src/type_manager.h" #include "src/type_manager.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, StructMember_Parses) { TEST_F(ParserImplTest, StructMember_Parses) {
auto i32 = auto i32 = tm()->Get(std::make_unique<ast::type::I32Type>());
TypeManager::Instance()->Get(std::make_unique<ast::type::I32Type>());
ParserImpl p{"a : i32;"}; auto p = parser("a : i32;");
auto m = p.struct_member(); auto m = p->struct_member();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_NE(m, nullptr); ASSERT_NE(m, nullptr);
EXPECT_EQ(m->name(), "a"); EXPECT_EQ(m->name(), "a");
EXPECT_EQ(m->type(), i32); EXPECT_EQ(m->type(), i32);
EXPECT_EQ(m->decorations().size(), 0); EXPECT_EQ(m->decorations().size(), 0);
TypeManager::Destroy();
} }
TEST_F(ParserImplTest, StructMember_ParsesWithDecoration) { TEST_F(ParserImplTest, StructMember_ParsesWithDecoration) {
auto i32 = auto i32 = tm()->Get(std::make_unique<ast::type::I32Type>());
TypeManager::Instance()->Get(std::make_unique<ast::type::I32Type>());
ParserImpl p{"[[offset 2]] a : i32;"}; auto p = parser("[[offset 2]] a : i32;");
auto m = p.struct_member(); auto m = p->struct_member();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_NE(m, nullptr); ASSERT_NE(m, nullptr);
EXPECT_EQ(m->name(), "a"); EXPECT_EQ(m->name(), "a");
@ -54,32 +49,30 @@ TEST_F(ParserImplTest, StructMember_ParsesWithDecoration) {
EXPECT_EQ(m->decorations().size(), 1); EXPECT_EQ(m->decorations().size(), 1);
EXPECT_TRUE(m->decorations()[0]->IsOffset()); EXPECT_TRUE(m->decorations()[0]->IsOffset());
EXPECT_EQ(m->decorations()[0]->AsOffset()->offset(), 2); EXPECT_EQ(m->decorations()[0]->AsOffset()->offset(), 2);
TypeManager::Destroy();
} }
TEST_F(ParserImplTest, StructMember_InvalidDecoration) { TEST_F(ParserImplTest, StructMember_InvalidDecoration) {
ParserImpl p{"[[offset nan]] a : i32;"}; auto p = parser("[[offset nan]] a : i32;");
auto m = p.struct_member(); auto m = p->struct_member();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(m, nullptr); ASSERT_EQ(m, nullptr);
EXPECT_EQ(p.error(), "1:10: invalid value for offset decoration"); EXPECT_EQ(p->error(), "1:10: invalid value for offset decoration");
} }
TEST_F(ParserImplTest, StructMember_InvalidVariable) { TEST_F(ParserImplTest, StructMember_InvalidVariable) {
ParserImpl p{"[[offset 4]] a : B;"}; auto p = parser("[[offset 4]] a : B;");
auto m = p.struct_member(); auto m = p->struct_member();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(m, nullptr); ASSERT_EQ(m, nullptr);
EXPECT_EQ(p.error(), "1:18: unknown type alias 'B'"); EXPECT_EQ(p->error(), "1:18: unknown type alias 'B'");
} }
TEST_F(ParserImplTest, StructMember_MissingSemicolon) { TEST_F(ParserImplTest, StructMember_MissingSemicolon) {
ParserImpl p{"a : i32"}; auto p = parser("a : i32");
auto m = p.struct_member(); auto m = p->struct_member();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(m, nullptr); ASSERT_EQ(m, nullptr);
EXPECT_EQ(p.error(), "1:8: missing ; for struct member"); EXPECT_EQ(p->error(), "1:8: missing ; for struct member");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -15,17 +15,16 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/ast/case_statement.h" #include "src/ast/case_statement.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, SwitchBody_Case) { TEST_F(ParserImplTest, SwitchBody_Case) {
ParserImpl p{"case 1: { a = 4; }"}; auto p = parser("case 1: { a = 4; }");
auto e = p.switch_body(); auto e = p->switch_body();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsCase()); ASSERT_TRUE(e->IsCase());
EXPECT_FALSE(e->IsDefault()); EXPECT_FALSE(e->IsDefault());
@ -34,57 +33,57 @@ TEST_F(ParserImplTest, SwitchBody_Case) {
} }
TEST_F(ParserImplTest, SwitchBody_Case_InvalidConstLiteral) { TEST_F(ParserImplTest, SwitchBody_Case_InvalidConstLiteral) {
ParserImpl p{"case a == 4: { a = 4; }"}; auto p = parser("case a == 4: { a = 4; }");
auto e = p.switch_body(); auto e = p->switch_body();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:6: unable to parse case conditional"); EXPECT_EQ(p->error(), "1:6: unable to parse case conditional");
} }
TEST_F(ParserImplTest, SwitchBody_Case_MissingConstLiteral) { TEST_F(ParserImplTest, SwitchBody_Case_MissingConstLiteral) {
ParserImpl p{"case: { a = 4; }"}; auto p = parser("case: { a = 4; }");
auto e = p.switch_body(); auto e = p->switch_body();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:5: unable to parse case conditional"); EXPECT_EQ(p->error(), "1:5: unable to parse case conditional");
} }
TEST_F(ParserImplTest, SwitchBody_Case_MissingColon) { TEST_F(ParserImplTest, SwitchBody_Case_MissingColon) {
ParserImpl p{"case 1 { a = 4; }"}; auto p = parser("case 1 { a = 4; }");
auto e = p.switch_body(); auto e = p->switch_body();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: missing : for case statement"); EXPECT_EQ(p->error(), "1:8: missing : for case statement");
} }
TEST_F(ParserImplTest, SwitchBody_Case_MissingBracketLeft) { TEST_F(ParserImplTest, SwitchBody_Case_MissingBracketLeft) {
ParserImpl p{"case 1: a = 4; }"}; auto p = parser("case 1: a = 4; }");
auto e = p.switch_body(); auto e = p->switch_body();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:9: missing { for case statement"); EXPECT_EQ(p->error(), "1:9: missing { for case statement");
} }
TEST_F(ParserImplTest, SwitchBody_Case_MissingBracketRight) { TEST_F(ParserImplTest, SwitchBody_Case_MissingBracketRight) {
ParserImpl p{"case 1: { a = 4; "}; auto p = parser("case 1: { a = 4; ");
auto e = p.switch_body(); auto e = p->switch_body();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:18: missing } for case statement"); EXPECT_EQ(p->error(), "1:18: missing } for case statement");
} }
TEST_F(ParserImplTest, SwitchBody_Case_InvalidCaseBody) { TEST_F(ParserImplTest, SwitchBody_Case_InvalidCaseBody) {
ParserImpl p{"case 1: { fn main() -> void {} }"}; auto p = parser("case 1: { fn main() -> void {} }");
auto e = p.switch_body(); auto e = p->switch_body();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:11: missing } for case statement"); EXPECT_EQ(p->error(), "1:11: missing } for case statement");
} }
TEST_F(ParserImplTest, SwitchBody_Default) { TEST_F(ParserImplTest, SwitchBody_Default) {
ParserImpl p{"default: { a = 4; }"}; auto p = parser("default: { a = 4; }");
auto e = p.switch_body(); auto e = p->switch_body();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsCase()); ASSERT_TRUE(e->IsCase());
EXPECT_TRUE(e->IsDefault()); EXPECT_TRUE(e->IsDefault());
@ -93,35 +92,35 @@ TEST_F(ParserImplTest, SwitchBody_Default) {
} }
TEST_F(ParserImplTest, SwitchBody_Default_MissingColon) { TEST_F(ParserImplTest, SwitchBody_Default_MissingColon) {
ParserImpl p{"default { a = 4; }"}; auto p = parser("default { a = 4; }");
auto e = p.switch_body(); auto e = p->switch_body();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:9: missing : for case statement"); EXPECT_EQ(p->error(), "1:9: missing : for case statement");
} }
TEST_F(ParserImplTest, SwitchBody_Default_MissingBracketLeft) { TEST_F(ParserImplTest, SwitchBody_Default_MissingBracketLeft) {
ParserImpl p{"default: a = 4; }"}; auto p = parser("default: a = 4; }");
auto e = p.switch_body(); auto e = p->switch_body();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:10: missing { for case statement"); EXPECT_EQ(p->error(), "1:10: missing { for case statement");
} }
TEST_F(ParserImplTest, SwitchBody_Default_MissingBracketRight) { TEST_F(ParserImplTest, SwitchBody_Default_MissingBracketRight) {
ParserImpl p{"default: { a = 4; "}; auto p = parser("default: { a = 4; ");
auto e = p.switch_body(); auto e = p->switch_body();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:19: missing } for case statement"); EXPECT_EQ(p->error(), "1:19: missing } for case statement");
} }
TEST_F(ParserImplTest, SwitchBody_Default_InvalidCaseBody) { TEST_F(ParserImplTest, SwitchBody_Default_InvalidCaseBody) {
ParserImpl p{"default: { fn main() -> void {} }"}; auto p = parser("default: { fn main() -> void {} }");
auto e = p.switch_body(); auto e = p->switch_body();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:12: missing } for case statement"); EXPECT_EQ(p->error(), "1:12: missing } for case statement");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -16,20 +16,19 @@
#include "src/ast/case_statement.h" #include "src/ast/case_statement.h"
#include "src/ast/switch_statement.h" #include "src/ast/switch_statement.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, SwitchStmt_WithoutDefault) { TEST_F(ParserImplTest, SwitchStmt_WithoutDefault) {
ParserImpl p{R"(switch(a) { auto p = parser(R"(switch(a) {
case 1: {} case 1: {}
case 2: {} case 2: {}
})"}; })");
auto e = p.switch_stmt(); auto e = p->switch_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsSwitch()); ASSERT_TRUE(e->IsSwitch());
ASSERT_EQ(e->body().size(), 2); ASSERT_EQ(e->body().size(), 2);
@ -38,22 +37,22 @@ TEST_F(ParserImplTest, SwitchStmt_WithoutDefault) {
} }
TEST_F(ParserImplTest, SwitchStmt_Empty) { TEST_F(ParserImplTest, SwitchStmt_Empty) {
ParserImpl p{"switch(a) { }"}; auto p = parser("switch(a) { }");
auto e = p.switch_stmt(); auto e = p->switch_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsSwitch()); ASSERT_TRUE(e->IsSwitch());
ASSERT_EQ(e->body().size(), 0); ASSERT_EQ(e->body().size(), 0);
} }
TEST_F(ParserImplTest, SwitchStmt_DefaultInMiddle) { TEST_F(ParserImplTest, SwitchStmt_DefaultInMiddle) {
ParserImpl p{R"(switch(a) { auto p = parser(R"(switch(a) {
case 1: {} case 1: {}
default: {} default: {}
case 2: {} case 2: {}
})"}; })");
auto e = p.switch_stmt(); auto e = p->switch_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsSwitch()); ASSERT_TRUE(e->IsSwitch());
@ -64,45 +63,45 @@ TEST_F(ParserImplTest, SwitchStmt_DefaultInMiddle) {
} }
TEST_F(ParserImplTest, SwitchStmt_InvalidExpression) { TEST_F(ParserImplTest, SwitchStmt_InvalidExpression) {
ParserImpl p{"switch(a=b) {}"}; auto p = parser("switch(a=b) {}");
auto e = p.switch_stmt(); auto e = p->switch_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:9: expected )"); EXPECT_EQ(p->error(), "1:9: expected )");
} }
TEST_F(ParserImplTest, SwitchStmt_MissingExpression) { TEST_F(ParserImplTest, SwitchStmt_MissingExpression) {
ParserImpl p{"switch {}"}; auto p = parser("switch {}");
auto e = p.switch_stmt(); auto e = p->switch_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: expected ("); EXPECT_EQ(p->error(), "1:8: expected (");
} }
TEST_F(ParserImplTest, SwitchStmt_MissingBracketLeft) { TEST_F(ParserImplTest, SwitchStmt_MissingBracketLeft) {
ParserImpl p{"switch(a) }"}; auto p = parser("switch(a) }");
auto e = p.switch_stmt(); auto e = p->switch_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:11: missing { for switch statement"); EXPECT_EQ(p->error(), "1:11: missing { for switch statement");
} }
TEST_F(ParserImplTest, SwitchStmt_MissingBracketRight) { TEST_F(ParserImplTest, SwitchStmt_MissingBracketRight) {
ParserImpl p{"switch(a) {"}; auto p = parser("switch(a) {");
auto e = p.switch_stmt(); auto e = p->switch_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:12: missing } for switch statement"); EXPECT_EQ(p->error(), "1:12: missing } for switch statement");
} }
TEST_F(ParserImplTest, SwitchStmt_InvalidBody) { TEST_F(ParserImplTest, SwitchStmt_InvalidBody) {
ParserImpl p{R"(switch(a) { auto p = parser(R"(switch(a) {
case: {} case: {}
})"}; })");
auto e = p.switch_stmt(); auto e = p->switch_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "2:7: unable to parse case conditional"); EXPECT_EQ(p->error(), "2:7: unable to parse case conditional");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -16,20 +16,19 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/ast/type/i32_type.h" #include "src/ast/type/i32_type.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, Empty) { TEST_F(ParserImplTest, Empty) {
ParserImpl p{""}; auto p = parser("");
ASSERT_TRUE(p.Parse()) << p.error(); ASSERT_TRUE(p->Parse()) << p->error();
} }
TEST_F(ParserImplTest, DISABLED_Parses) { TEST_F(ParserImplTest, DISABLED_Parses) {
ParserImpl p{R"( auto p = parser(R"(
import "GLSL.std.430" as glsl; import "GLSL.std.430" as glsl;
[[location 0]] var<out> gl_FragColor : vec4<f32>; [[location 0]] var<out> gl_FragColor : vec4<f32>;
@ -37,41 +36,41 @@ import "GLSL.std.430" as glsl;
fn main() -> void { fn main() -> void {
gl_FragColor = vec4<f32>(.4, .2, .3, 1); gl_FragColor = vec4<f32>(.4, .2, .3, 1);
} }
)"}; )");
ASSERT_TRUE(p.Parse()) << p.error(); ASSERT_TRUE(p->Parse()) << p->error();
auto m = p.module(); auto m = p->module();
ASSERT_EQ(1, m.imports().size()); ASSERT_EQ(1, m.imports().size());
// TODO(dsinclair) check rest of AST ... // TODO(dsinclair) check rest of AST ...
} }
TEST_F(ParserImplTest, DISABLED_HandlesError) { TEST_F(ParserImplTest, DISABLED_HandlesError) {
ParserImpl p{R"( auto p = parser(R"(
import "GLSL.std.430" as glsl; import "GLSL.std.430" as glsl;
fn main() -> { # missing return type fn main() -> { # missing return type
return; return;
})"}; })");
ASSERT_FALSE(p.Parse()); ASSERT_FALSE(p->Parse());
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "4:15: missing return type for function"); EXPECT_EQ(p->error(), "4:15: missing return type for function");
} }
TEST_F(ParserImplTest, GetRegisteredType) { TEST_F(ParserImplTest, GetRegisteredType) {
ParserImpl p{""}; auto p = parser("");
ast::type::I32Type i32; ast::type::I32Type i32;
p.register_alias("my_alias", &i32); p->register_alias("my_alias", &i32);
auto alias = p.get_alias("my_alias"); auto alias = p->get_alias("my_alias");
ASSERT_NE(alias, nullptr); ASSERT_NE(alias, nullptr);
ASSERT_EQ(alias, &i32); ASSERT_EQ(alias, &i32);
} }
TEST_F(ParserImplTest, GetUnregisteredType) { TEST_F(ParserImplTest, GetUnregisteredType) {
ParserImpl p{""}; auto p = parser("");
auto alias = p.get_alias("my_alias"); auto alias = p->get_alias("my_alias");
ASSERT_EQ(alias, nullptr); ASSERT_EQ(alias, nullptr);
} }

View File

@ -0,0 +1,58 @@
// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_READER_WGSL_PARSER_IMPL_TEST_HELPER_H_
#define SRC_READER_WGSL_PARSER_IMPL_TEST_HELPER_H_
#include <memory>
#include <string>
#include "gtest/gtest.h"
#include "src/context.h"
#include "src/reader/wgsl/parser_impl.h"
namespace tint {
namespace reader {
namespace wgsl {
class ParserImplTest : public testing::Test {
public:
ParserImplTest() = default;
~ParserImplTest() = default;
void SetUp() { ctx_.type_mgr = &tm_; }
void TearDown() {
impl_ = nullptr;
ctx_.type_mgr = nullptr;
}
ParserImpl* parser(const std::string& str) {
impl_ = std::make_unique<ParserImpl>(ctx_, str);
return impl_.get();
}
TypeManager* tm() { return &tm_; }
private:
std::unique_ptr<ParserImpl> impl_;
Context ctx_;
TypeManager tm_;
};
} // namespace wgsl
} // namespace reader
} // namespace tint
#endif // SRC_READER_WGSL_PARSER_IMPL_TEST_HELPER_H_

View File

@ -17,32 +17,28 @@
#include "src/ast/type/i32_type.h" #include "src/ast/type/i32_type.h"
#include "src/ast/type/struct_type.h" #include "src/ast/type/struct_type.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
#include "src/type_manager.h" #include "src/type_manager.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, TypeDecl_ParsesType) { TEST_F(ParserImplTest, TypeDecl_ParsesType) {
auto tm = TypeManager::Instance(); auto i32 = tm()->Get(std::make_unique<ast::type::I32Type>());
auto i32 = tm->Get(std::make_unique<ast::type::I32Type>());
ParserImpl p{"type a = i32"}; auto p = parser("type a = i32");
auto t = p.type_alias(); auto t = p->type_alias();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_NE(t, nullptr); ASSERT_NE(t, nullptr);
ASSERT_TRUE(t->type()->IsI32()); ASSERT_TRUE(t->type()->IsI32());
ASSERT_EQ(t->type(), i32); ASSERT_EQ(t->type(), i32);
TypeManager::Destroy();
} }
TEST_F(ParserImplTest, TypeDecl_ParsesStruct) { TEST_F(ParserImplTest, TypeDecl_ParsesStruct) {
ParserImpl p{"type a = struct { b: i32; c: f32;}"}; auto p = parser("type a = struct { b: i32; c: f32;}");
auto t = p.type_alias(); auto t = p->type_alias();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_NE(t, nullptr); ASSERT_NE(t, nullptr);
EXPECT_EQ(t->name(), "a"); EXPECT_EQ(t->name(), "a");
ASSERT_TRUE(t->type()->IsStruct()); ASSERT_TRUE(t->type()->IsStruct());
@ -52,43 +48,43 @@ TEST_F(ParserImplTest, TypeDecl_ParsesStruct) {
} }
TEST_F(ParserImplTest, TypeDecl_MissingIdent) { TEST_F(ParserImplTest, TypeDecl_MissingIdent) {
ParserImpl p{"type = i32"}; auto p = parser("type = i32");
auto t = p.type_alias(); auto t = p->type_alias();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
EXPECT_EQ(p.error(), "1:6: missing identifier for type alias"); EXPECT_EQ(p->error(), "1:6: missing identifier for type alias");
} }
TEST_F(ParserImplTest, TypeDecl_InvalidIdent) { TEST_F(ParserImplTest, TypeDecl_InvalidIdent) {
ParserImpl p{"type 123 = i32"}; auto p = parser("type 123 = i32");
auto t = p.type_alias(); auto t = p->type_alias();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
EXPECT_EQ(p.error(), "1:6: missing identifier for type alias"); EXPECT_EQ(p->error(), "1:6: missing identifier for type alias");
} }
TEST_F(ParserImplTest, TypeDecl_MissingEqual) { TEST_F(ParserImplTest, TypeDecl_MissingEqual) {
ParserImpl p{"type a i32"}; auto p = parser("type a i32");
auto t = p.type_alias(); auto t = p->type_alias();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
EXPECT_EQ(p.error(), "1:8: missing = for type alias"); EXPECT_EQ(p->error(), "1:8: missing = for type alias");
} }
TEST_F(ParserImplTest, TypeDecl_InvalidType) { TEST_F(ParserImplTest, TypeDecl_InvalidType) {
ParserImpl p{"type a = B"}; auto p = parser("type a = B");
auto t = p.type_alias(); auto t = p->type_alias();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
EXPECT_EQ(p.error(), "1:10: unknown type alias 'B'"); EXPECT_EQ(p->error(), "1:10: unknown type alias 'B'");
} }
TEST_F(ParserImplTest, TypeDecl_InvalidStruct) { TEST_F(ParserImplTest, TypeDecl_InvalidStruct) {
ParserImpl p{"type a = [[block]] {}"}; auto p = parser("type a = [[block]] {}");
auto t = p.type_alias(); auto t = p->type_alias();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
EXPECT_EQ(p.error(), "1:20: missing struct declaration"); EXPECT_EQ(p->error(), "1:20: missing struct declaration");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -24,33 +24,31 @@
#include "src/ast/type/u32_type.h" #include "src/ast/type/u32_type.h"
#include "src/ast/type/vector_type.h" #include "src/ast/type/vector_type.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
#include "src/type_manager.h" #include "src/type_manager.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, TypeDecl_Invalid) { TEST_F(ParserImplTest, TypeDecl_Invalid) {
ParserImpl p{"1234"}; auto p = parser("1234");
auto t = p.type_decl(); auto t = p->type_decl();
EXPECT_EQ(t, nullptr); EXPECT_EQ(t, nullptr);
EXPECT_FALSE(p.has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, TypeDecl_Identifier) { TEST_F(ParserImplTest, TypeDecl_Identifier) {
ParserImpl p{"A"}; auto p = parser("A");
auto tm = TypeManager::Instance(); auto int_type = tm()->Get(std::make_unique<ast::type::I32Type>());
auto int_type = tm->Get(std::make_unique<ast::type::I32Type>());
// Pre-register to make sure that it's the same type. // Pre-register to make sure that it's the same type.
auto alias_type = auto alias_type =
tm->Get(std::make_unique<ast::type::AliasType>("A", int_type)); tm()->Get(std::make_unique<ast::type::AliasType>("A", int_type));
p.register_alias("A", alias_type); p->register_alias("A", alias_type);
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr); ASSERT_NE(t, nullptr);
EXPECT_EQ(t, alias_type); EXPECT_EQ(t, alias_type);
ASSERT_TRUE(t->IsAlias()); ASSERT_TRUE(t->IsAlias());
@ -58,73 +56,59 @@ TEST_F(ParserImplTest, TypeDecl_Identifier) {
auto alias = t->AsAlias(); auto alias = t->AsAlias();
EXPECT_EQ(alias->name(), "A"); EXPECT_EQ(alias->name(), "A");
EXPECT_EQ(alias->type(), int_type); EXPECT_EQ(alias->type(), int_type);
TypeManager::Destroy();
} }
TEST_F(ParserImplTest, TypeDecl_Identifier_NotFound) { TEST_F(ParserImplTest, TypeDecl_Identifier_NotFound) {
ParserImpl p{"B"}; auto p = parser("B");
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
EXPECT_TRUE(p.has_error()); EXPECT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:1: unknown type alias 'B'"); EXPECT_EQ(p->error(), "1:1: unknown type alias 'B'");
} }
TEST_F(ParserImplTest, TypeDecl_Bool) { TEST_F(ParserImplTest, TypeDecl_Bool) {
ParserImpl p{"bool"}; auto p = parser("bool");
auto tm = TypeManager::Instance(); auto bool_type = tm()->Get(std::make_unique<ast::type::BoolType>());
auto bool_type = tm->Get(std::make_unique<ast::type::BoolType>());
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr); ASSERT_NE(t, nullptr);
EXPECT_EQ(t, bool_type); EXPECT_EQ(t, bool_type);
ASSERT_TRUE(t->IsBool()); ASSERT_TRUE(t->IsBool());
TypeManager::Destroy();
} }
TEST_F(ParserImplTest, TypeDecl_F32) { TEST_F(ParserImplTest, TypeDecl_F32) {
ParserImpl p{"f32"}; auto p = parser("f32");
auto tm = TypeManager::Instance(); auto float_type = tm()->Get(std::make_unique<ast::type::F32Type>());
auto float_type = tm->Get(std::make_unique<ast::type::F32Type>());
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr); ASSERT_NE(t, nullptr);
EXPECT_EQ(t, float_type); EXPECT_EQ(t, float_type);
ASSERT_TRUE(t->IsF32()); ASSERT_TRUE(t->IsF32());
TypeManager::Destroy();
} }
TEST_F(ParserImplTest, TypeDecl_I32) { TEST_F(ParserImplTest, TypeDecl_I32) {
ParserImpl p{"i32"}; auto p = parser("i32");
auto tm = TypeManager::Instance(); auto int_type = tm()->Get(std::make_unique<ast::type::I32Type>());
auto int_type = tm->Get(std::make_unique<ast::type::I32Type>());
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr); ASSERT_NE(t, nullptr);
EXPECT_EQ(t, int_type); EXPECT_EQ(t, int_type);
ASSERT_TRUE(t->IsI32()); ASSERT_TRUE(t->IsI32());
TypeManager::Destroy();
} }
TEST_F(ParserImplTest, TypeDecl_U32) { TEST_F(ParserImplTest, TypeDecl_U32) {
ParserImpl p{"u32"}; auto p = parser("u32");
auto tm = TypeManager::Instance(); auto uint_type = tm()->Get(std::make_unique<ast::type::U32Type>());
auto uint_type = tm->Get(std::make_unique<ast::type::U32Type>());
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr); ASSERT_NE(t, nullptr);
EXPECT_EQ(t, uint_type); EXPECT_EQ(t, uint_type);
ASSERT_TRUE(t->IsU32()); ASSERT_TRUE(t->IsU32());
TypeManager::Destroy();
} }
struct VecData { struct VecData {
@ -135,13 +119,35 @@ inline std::ostream& operator<<(std::ostream& out, VecData data) {
out << std::string(data.input); out << std::string(data.input);
return out; return out;
} }
using VecTest = testing::TestWithParam<VecData>; class VecTest : public testing::TestWithParam<VecData> {
public:
VecTest() = default;
~VecTest() = default;
void SetUp() { ctx_.type_mgr = &tm_; }
void TearDown() {
impl_ = nullptr;
ctx_.type_mgr = nullptr;
}
ParserImpl* parser(const std::string& str) {
impl_ = std::make_unique<ParserImpl>(ctx_, str);
return impl_.get();
}
private:
std::unique_ptr<ParserImpl> impl_;
Context ctx_;
TypeManager tm_;
};
TEST_P(VecTest, Parse) { TEST_P(VecTest, Parse) {
auto params = GetParam(); auto params = GetParam();
ParserImpl p{params.input}; auto p = parser(params.input);
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr); ASSERT_NE(t, nullptr);
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
EXPECT_TRUE(t->IsVector()); EXPECT_TRUE(t->IsVector());
EXPECT_EQ(t->AsVector()->size(), params.count); EXPECT_EQ(t->AsVector()->size(), params.count);
} }
@ -151,14 +157,36 @@ INSTANTIATE_TEST_SUITE_P(ParserImplTest,
VecData{"vec3<f32>", 3}, VecData{"vec3<f32>", 3},
VecData{"vec4<f32>", 4})); VecData{"vec4<f32>", 4}));
using VecMissingGreaterThanTest = testing::TestWithParam<VecData>; class VecMissingGreaterThanTest : public testing::TestWithParam<VecData> {
public:
VecMissingGreaterThanTest() = default;
~VecMissingGreaterThanTest() = default;
void SetUp() { ctx_.type_mgr = &tm_; }
void TearDown() {
impl_ = nullptr;
ctx_.type_mgr = nullptr;
}
ParserImpl* parser(const std::string& str) {
impl_ = std::make_unique<ParserImpl>(ctx_, str);
return impl_.get();
}
private:
std::unique_ptr<ParserImpl> impl_;
Context ctx_;
TypeManager tm_;
};
TEST_P(VecMissingGreaterThanTest, Handles_Missing_GreaterThan) { TEST_P(VecMissingGreaterThanTest, Handles_Missing_GreaterThan) {
auto params = GetParam(); auto params = GetParam();
ParserImpl p{params.input}; auto p = parser(params.input);
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:9: missing > for vector"); ASSERT_EQ(p->error(), "1:9: missing > for vector");
} }
INSTANTIATE_TEST_SUITE_P(ParserImplTest, INSTANTIATE_TEST_SUITE_P(ParserImplTest,
VecMissingGreaterThanTest, VecMissingGreaterThanTest,
@ -166,14 +194,36 @@ INSTANTIATE_TEST_SUITE_P(ParserImplTest,
VecData{"vec3<f32", 3}, VecData{"vec3<f32", 3},
VecData{"vec4<f32", 4})); VecData{"vec4<f32", 4}));
using VecMissingLessThanTest = testing::TestWithParam<VecData>; class VecMissingLessThanTest : public testing::TestWithParam<VecData> {
public:
VecMissingLessThanTest() = default;
~VecMissingLessThanTest() = default;
void SetUp() { ctx_.type_mgr = &tm_; }
void TearDown() {
impl_ = nullptr;
ctx_.type_mgr = nullptr;
}
ParserImpl* parser(const std::string& str) {
impl_ = std::make_unique<ParserImpl>(ctx_, str);
return impl_.get();
}
private:
std::unique_ptr<ParserImpl> impl_;
Context ctx_;
TypeManager tm_;
};
TEST_P(VecMissingLessThanTest, Handles_Missing_GreaterThan) { TEST_P(VecMissingLessThanTest, Handles_Missing_GreaterThan) {
auto params = GetParam(); auto params = GetParam();
ParserImpl p{params.input}; auto p = parser(params.input);
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:5: missing < for vector"); ASSERT_EQ(p->error(), "1:5: missing < for vector");
} }
INSTANTIATE_TEST_SUITE_P(ParserImplTest, INSTANTIATE_TEST_SUITE_P(ParserImplTest,
VecMissingLessThanTest, VecMissingLessThanTest,
@ -181,14 +231,36 @@ INSTANTIATE_TEST_SUITE_P(ParserImplTest,
VecData{"vec3", 3}, VecData{"vec3", 3},
VecData{"vec4", 4})); VecData{"vec4", 4}));
using VecBadType = testing::TestWithParam<VecData>; class VecBadType : public testing::TestWithParam<VecData> {
public:
VecBadType() = default;
~VecBadType() = default;
void SetUp() { ctx_.type_mgr = &tm_; }
void TearDown() {
impl_ = nullptr;
ctx_.type_mgr = nullptr;
}
ParserImpl* parser(const std::string& str) {
impl_ = std::make_unique<ParserImpl>(ctx_, str);
return impl_.get();
}
private:
std::unique_ptr<ParserImpl> impl_;
Context ctx_;
TypeManager tm_;
};
TEST_P(VecBadType, Handles_Unknown_Type) { TEST_P(VecBadType, Handles_Unknown_Type) {
auto params = GetParam(); auto params = GetParam();
ParserImpl p{params.input}; auto p = parser(params.input);
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:6: unknown type alias 'unknown'"); ASSERT_EQ(p->error(), "1:6: unknown type alias 'unknown'");
} }
INSTANTIATE_TEST_SUITE_P(ParserImplTest, INSTANTIATE_TEST_SUITE_P(ParserImplTest,
VecBadType, VecBadType,
@ -196,14 +268,36 @@ INSTANTIATE_TEST_SUITE_P(ParserImplTest,
VecData{"vec3<unknown", 3}, VecData{"vec3<unknown", 3},
VecData{"vec4<unknown", 4})); VecData{"vec4<unknown", 4}));
using VecMissingType = testing::TestWithParam<VecData>; class VecMissingType : public testing::TestWithParam<VecData> {
public:
VecMissingType() = default;
~VecMissingType() = default;
void SetUp() { ctx_.type_mgr = &tm_; }
void TearDown() {
impl_ = nullptr;
ctx_.type_mgr = nullptr;
}
ParserImpl* parser(const std::string& str) {
impl_ = std::make_unique<ParserImpl>(ctx_, str);
return impl_.get();
}
private:
std::unique_ptr<ParserImpl> impl_;
Context ctx_;
TypeManager tm_;
};
TEST_P(VecMissingType, Handles_Missing_Type) { TEST_P(VecMissingType, Handles_Missing_Type) {
auto params = GetParam(); auto params = GetParam();
ParserImpl p{params.input}; auto p = parser(params.input);
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:6: unable to determine subtype for vector"); ASSERT_EQ(p->error(), "1:6: unable to determine subtype for vector");
} }
INSTANTIATE_TEST_SUITE_P(ParserImplTest, INSTANTIATE_TEST_SUITE_P(ParserImplTest,
VecMissingType, VecMissingType,
@ -212,10 +306,10 @@ INSTANTIATE_TEST_SUITE_P(ParserImplTest,
VecData{"vec4<>", 4})); VecData{"vec4<>", 4}));
TEST_F(ParserImplTest, TypeDecl_Ptr) { TEST_F(ParserImplTest, TypeDecl_Ptr) {
ParserImpl p{"ptr<function, f32>"}; auto p = parser("ptr<function, f32>");
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr) << p.error(); ASSERT_NE(t, nullptr) << p->error();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_TRUE(t->IsPointer()); ASSERT_TRUE(t->IsPointer());
auto ptr = t->AsPointer(); auto ptr = t->AsPointer();
@ -224,10 +318,10 @@ TEST_F(ParserImplTest, TypeDecl_Ptr) {
} }
TEST_F(ParserImplTest, TypeDecl_Ptr_ToVec) { TEST_F(ParserImplTest, TypeDecl_Ptr_ToVec) {
ParserImpl p{"ptr<function, vec2<f32>>"}; auto p = parser("ptr<function, vec2<f32>>");
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr) << p.error(); ASSERT_NE(t, nullptr) << p->error();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_TRUE(t->IsPointer()); ASSERT_TRUE(t->IsPointer());
auto ptr = t->AsPointer(); auto ptr = t->AsPointer();
@ -240,74 +334,74 @@ TEST_F(ParserImplTest, TypeDecl_Ptr_ToVec) {
} }
TEST_F(ParserImplTest, TypeDecl_Ptr_MissingLessThan) { TEST_F(ParserImplTest, TypeDecl_Ptr_MissingLessThan) {
ParserImpl p{"ptr private, f32>"}; auto p = parser("ptr private, f32>");
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:5: missing < for ptr declaration"); ASSERT_EQ(p->error(), "1:5: missing < for ptr declaration");
} }
TEST_F(ParserImplTest, TypeDecl_Ptr_MissingGreaterThan) { TEST_F(ParserImplTest, TypeDecl_Ptr_MissingGreaterThan) {
ParserImpl p{"ptr<function, f32"}; auto p = parser("ptr<function, f32");
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:18: missing > for ptr declaration"); ASSERT_EQ(p->error(), "1:18: missing > for ptr declaration");
} }
TEST_F(ParserImplTest, TypeDecl_Ptr_MissingComma) { TEST_F(ParserImplTest, TypeDecl_Ptr_MissingComma) {
ParserImpl p{"ptr<function f32>"}; auto p = parser("ptr<function f32>");
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:14: missing , for ptr declaration"); ASSERT_EQ(p->error(), "1:14: missing , for ptr declaration");
} }
TEST_F(ParserImplTest, TypeDecl_Ptr_MissingStorageClass) { TEST_F(ParserImplTest, TypeDecl_Ptr_MissingStorageClass) {
ParserImpl p{"ptr<, f32>"}; auto p = parser("ptr<, f32>");
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:5: missing storage class for ptr declaration"); ASSERT_EQ(p->error(), "1:5: missing storage class for ptr declaration");
} }
TEST_F(ParserImplTest, TypeDecl_Ptr_MissingParams) { TEST_F(ParserImplTest, TypeDecl_Ptr_MissingParams) {
ParserImpl p{"ptr<>"}; auto p = parser("ptr<>");
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:5: missing storage class for ptr declaration"); ASSERT_EQ(p->error(), "1:5: missing storage class for ptr declaration");
} }
TEST_F(ParserImplTest, TypeDecl_Ptr_MissingType) { TEST_F(ParserImplTest, TypeDecl_Ptr_MissingType) {
ParserImpl p{"ptr<function,>"}; auto p = parser("ptr<function,>");
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:14: missing type for ptr declaration"); ASSERT_EQ(p->error(), "1:14: missing type for ptr declaration");
} }
TEST_F(ParserImplTest, TypeDecl_Ptr_BadStorageClass) { TEST_F(ParserImplTest, TypeDecl_Ptr_BadStorageClass) {
ParserImpl p{"ptr<unknown, f32>"}; auto p = parser("ptr<unknown, f32>");
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:5: missing storage class for ptr declaration"); ASSERT_EQ(p->error(), "1:5: missing storage class for ptr declaration");
} }
TEST_F(ParserImplTest, TypeDecl_Ptr_BadType) { TEST_F(ParserImplTest, TypeDecl_Ptr_BadType) {
ParserImpl p{"ptr<function, unknown>"}; auto p = parser("ptr<function, unknown>");
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:15: unknown type alias 'unknown'"); ASSERT_EQ(p->error(), "1:15: unknown type alias 'unknown'");
} }
TEST_F(ParserImplTest, TypeDecl_Array) { TEST_F(ParserImplTest, TypeDecl_Array) {
ParserImpl p{"array<f32, 5>"}; auto p = parser("array<f32, 5>");
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr); ASSERT_NE(t, nullptr);
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_TRUE(t->IsArray()); ASSERT_TRUE(t->IsArray());
auto a = t->AsArray(); auto a = t->AsArray();
@ -317,10 +411,10 @@ TEST_F(ParserImplTest, TypeDecl_Array) {
} }
TEST_F(ParserImplTest, TypeDecl_Array_Runtime) { TEST_F(ParserImplTest, TypeDecl_Array_Runtime) {
ParserImpl p{"array<u32>"}; auto p = parser("array<u32>");
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr); ASSERT_NE(t, nullptr);
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_TRUE(t->IsArray()); ASSERT_TRUE(t->IsArray());
auto a = t->AsArray(); auto a = t->AsArray();
@ -329,59 +423,59 @@ TEST_F(ParserImplTest, TypeDecl_Array_Runtime) {
} }
TEST_F(ParserImplTest, TypeDecl_Array_BadType) { TEST_F(ParserImplTest, TypeDecl_Array_BadType) {
ParserImpl p{"array<unknown, 3>"}; auto p = parser("array<unknown, 3>");
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:7: unknown type alias 'unknown'"); ASSERT_EQ(p->error(), "1:7: unknown type alias 'unknown'");
} }
TEST_F(ParserImplTest, TypeDecl_Array_ZeroSize) { TEST_F(ParserImplTest, TypeDecl_Array_ZeroSize) {
ParserImpl p{"array<f32, 0>"}; auto p = parser("array<f32, 0>");
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:12: invalid size for array declaration"); ASSERT_EQ(p->error(), "1:12: invalid size for array declaration");
} }
TEST_F(ParserImplTest, TypeDecl_Array_NegativeSize) { TEST_F(ParserImplTest, TypeDecl_Array_NegativeSize) {
ParserImpl p{"array<f32, -1>"}; auto p = parser("array<f32, -1>");
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:12: invalid size for array declaration"); ASSERT_EQ(p->error(), "1:12: invalid size for array declaration");
} }
TEST_F(ParserImplTest, TypeDecl_Array_BadSize) { TEST_F(ParserImplTest, TypeDecl_Array_BadSize) {
ParserImpl p{"array<f32, invalid>"}; auto p = parser("array<f32, invalid>");
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:12: missing size of array declaration"); ASSERT_EQ(p->error(), "1:12: missing size of array declaration");
} }
TEST_F(ParserImplTest, TypeDecl_Array_MissingLessThan) { TEST_F(ParserImplTest, TypeDecl_Array_MissingLessThan) {
ParserImpl p{"array f32>"}; auto p = parser("array f32>");
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:7: missing < for array declaration"); ASSERT_EQ(p->error(), "1:7: missing < for array declaration");
} }
TEST_F(ParserImplTest, TypeDecl_Array_MissingGreaterThan) { TEST_F(ParserImplTest, TypeDecl_Array_MissingGreaterThan) {
ParserImpl p{"array<f32"}; auto p = parser("array<f32");
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:10: missing > for array declaration"); ASSERT_EQ(p->error(), "1:10: missing > for array declaration");
} }
TEST_F(ParserImplTest, TypeDecl_Array_MissingComma) { TEST_F(ParserImplTest, TypeDecl_Array_MissingComma) {
ParserImpl p{"array<f32 3>"}; auto p = parser("array<f32 3>");
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:11: missing > for array declaration"); ASSERT_EQ(p->error(), "1:11: missing > for array declaration");
} }
struct MatrixData { struct MatrixData {
@ -393,13 +487,35 @@ inline std::ostream& operator<<(std::ostream& out, MatrixData data) {
out << std::string(data.input); out << std::string(data.input);
return out; return out;
} }
using MatrixTest = testing::TestWithParam<MatrixData>; class MatrixTest : public testing::TestWithParam<MatrixData> {
public:
MatrixTest() = default;
~MatrixTest() = default;
void SetUp() { ctx_.type_mgr = &tm_; }
void TearDown() {
impl_ = nullptr;
ctx_.type_mgr = nullptr;
}
ParserImpl* parser(const std::string& str) {
impl_ = std::make_unique<ParserImpl>(ctx_, str);
return impl_.get();
}
private:
std::unique_ptr<ParserImpl> impl_;
Context ctx_;
TypeManager tm_;
};
TEST_P(MatrixTest, Parse) { TEST_P(MatrixTest, Parse) {
auto params = GetParam(); auto params = GetParam();
ParserImpl p{params.input}; auto p = parser(params.input);
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr); ASSERT_NE(t, nullptr);
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
EXPECT_TRUE(t->IsMatrix()); EXPECT_TRUE(t->IsMatrix());
auto mat = t->AsMatrix(); auto mat = t->AsMatrix();
EXPECT_EQ(mat->rows(), params.rows); EXPECT_EQ(mat->rows(), params.rows);
@ -417,14 +533,35 @@ INSTANTIATE_TEST_SUITE_P(ParserImplTest,
MatrixData{"mat4x3<f32>", 4, 3}, MatrixData{"mat4x3<f32>", 4, 3},
MatrixData{"mat4x4<f32>", 4, 4})); MatrixData{"mat4x4<f32>", 4, 4}));
using MatrixMissingGreaterThanTest = testing::TestWithParam<MatrixData>; class MatrixMissingGreaterThanTest : public testing::TestWithParam<MatrixData> {
public:
MatrixMissingGreaterThanTest() = default;
~MatrixMissingGreaterThanTest() = default;
void SetUp() { ctx_.type_mgr = &tm_; }
void TearDown() {
impl_ = nullptr;
ctx_.type_mgr = nullptr;
}
ParserImpl* parser(const std::string& str) {
impl_ = std::make_unique<ParserImpl>(ctx_, str);
return impl_.get();
}
private:
std::unique_ptr<ParserImpl> impl_;
Context ctx_;
TypeManager tm_;
};
TEST_P(MatrixMissingGreaterThanTest, Handles_Missing_GreaterThan) { TEST_P(MatrixMissingGreaterThanTest, Handles_Missing_GreaterThan) {
auto params = GetParam(); auto params = GetParam();
ParserImpl p{params.input}; auto p = parser(params.input);
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:11: missing > for matrix"); ASSERT_EQ(p->error(), "1:11: missing > for matrix");
} }
INSTANTIATE_TEST_SUITE_P(ParserImplTest, INSTANTIATE_TEST_SUITE_P(ParserImplTest,
MatrixMissingGreaterThanTest, MatrixMissingGreaterThanTest,
@ -438,14 +575,35 @@ INSTANTIATE_TEST_SUITE_P(ParserImplTest,
MatrixData{"mat4x3<f32", 4, 3}, MatrixData{"mat4x3<f32", 4, 3},
MatrixData{"mat4x4<f32", 4, 4})); MatrixData{"mat4x4<f32", 4, 4}));
using MatrixMissingLessThanTest = testing::TestWithParam<MatrixData>; class MatrixMissingLessThanTest : public testing::TestWithParam<MatrixData> {
public:
MatrixMissingLessThanTest() = default;
~MatrixMissingLessThanTest() = default;
void SetUp() { ctx_.type_mgr = &tm_; }
void TearDown() {
impl_ = nullptr;
ctx_.type_mgr = nullptr;
}
ParserImpl* parser(const std::string& str) {
impl_ = std::make_unique<ParserImpl>(ctx_, str);
return impl_.get();
}
private:
std::unique_ptr<ParserImpl> impl_;
Context ctx_;
TypeManager tm_;
};
TEST_P(MatrixMissingLessThanTest, Handles_Missing_GreaterThan) { TEST_P(MatrixMissingLessThanTest, Handles_Missing_GreaterThan) {
auto params = GetParam(); auto params = GetParam();
ParserImpl p{params.input}; auto p = parser(params.input);
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:8: missing < for matrix"); ASSERT_EQ(p->error(), "1:8: missing < for matrix");
} }
INSTANTIATE_TEST_SUITE_P(ParserImplTest, INSTANTIATE_TEST_SUITE_P(ParserImplTest,
MatrixMissingLessThanTest, MatrixMissingLessThanTest,
@ -459,14 +617,35 @@ INSTANTIATE_TEST_SUITE_P(ParserImplTest,
MatrixData{"mat4x3 f32>", 4, 3}, MatrixData{"mat4x3 f32>", 4, 3},
MatrixData{"mat4x4 f32>", 4, 4})); MatrixData{"mat4x4 f32>", 4, 4}));
using MatrixBadType = testing::TestWithParam<MatrixData>; class MatrixBadType : public testing::TestWithParam<MatrixData> {
public:
MatrixBadType() = default;
~MatrixBadType() = default;
void SetUp() { ctx_.type_mgr = &tm_; }
void TearDown() {
impl_ = nullptr;
ctx_.type_mgr = nullptr;
}
ParserImpl* parser(const std::string& str) {
impl_ = std::make_unique<ParserImpl>(ctx_, str);
return impl_.get();
}
private:
std::unique_ptr<ParserImpl> impl_;
Context ctx_;
TypeManager tm_;
};
TEST_P(MatrixBadType, Handles_Unknown_Type) { TEST_P(MatrixBadType, Handles_Unknown_Type) {
auto params = GetParam(); auto params = GetParam();
ParserImpl p{params.input}; auto p = parser(params.input);
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:8: unknown type alias 'unknown'"); ASSERT_EQ(p->error(), "1:8: unknown type alias 'unknown'");
} }
INSTANTIATE_TEST_SUITE_P(ParserImplTest, INSTANTIATE_TEST_SUITE_P(ParserImplTest,
MatrixBadType, MatrixBadType,
@ -480,14 +659,35 @@ INSTANTIATE_TEST_SUITE_P(ParserImplTest,
MatrixData{"mat4x3<unknown>", 4, 3}, MatrixData{"mat4x3<unknown>", 4, 3},
MatrixData{"mat4x4<unknown>", 4, 4})); MatrixData{"mat4x4<unknown>", 4, 4}));
using MatrixMissingType = testing::TestWithParam<MatrixData>; class MatrixMissingType : public testing::TestWithParam<MatrixData> {
public:
MatrixMissingType() = default;
~MatrixMissingType() = default;
void SetUp() { ctx_.type_mgr = &tm_; }
void TearDown() {
impl_ = nullptr;
ctx_.type_mgr = nullptr;
}
ParserImpl* parser(const std::string& str) {
impl_ = std::make_unique<ParserImpl>(ctx_, str);
return impl_.get();
}
private:
std::unique_ptr<ParserImpl> impl_;
Context ctx_;
TypeManager tm_;
};
TEST_P(MatrixMissingType, Handles_Missing_Type) { TEST_P(MatrixMissingType, Handles_Missing_Type) {
auto params = GetParam(); auto params = GetParam();
ParserImpl p{params.input}; auto p = parser(params.input);
auto t = p.type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:8: unable to determine subtype for matrix"); ASSERT_EQ(p->error(), "1:8: unable to determine subtype for matrix");
} }
INSTANTIATE_TEST_SUITE_P(ParserImplTest, INSTANTIATE_TEST_SUITE_P(ParserImplTest,
MatrixMissingType, MatrixMissingType,

View File

@ -21,17 +21,16 @@
#include "src/ast/unary_method_expression.h" #include "src/ast/unary_method_expression.h"
#include "src/ast/unary_op_expression.h" #include "src/ast/unary_op_expression.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, UnaryExpression_Postix) { TEST_F(ParserImplTest, UnaryExpression_Postix) {
ParserImpl p{"a[2]"}; auto p = parser("a[2]");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsArrayAccessor()); ASSERT_TRUE(e->IsArrayAccessor());
@ -49,9 +48,9 @@ TEST_F(ParserImplTest, UnaryExpression_Postix) {
} }
TEST_F(ParserImplTest, UnaryExpression_Minus) { TEST_F(ParserImplTest, UnaryExpression_Minus) {
ParserImpl p{"- 1"}; auto p = parser("- 1");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryOp()); ASSERT_TRUE(e->IsUnaryOp());
@ -67,17 +66,17 @@ TEST_F(ParserImplTest, UnaryExpression_Minus) {
} }
TEST_F(ParserImplTest, UnaryExpression_Minus_InvalidRHS) { TEST_F(ParserImplTest, UnaryExpression_Minus_InvalidRHS) {
ParserImpl p{"-if(a) {}"}; auto p = parser("-if(a) {}");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:2: unable to parse right side of - expression"); EXPECT_EQ(p->error(), "1:2: unable to parse right side of - expression");
} }
TEST_F(ParserImplTest, UnaryExpression_Bang) { TEST_F(ParserImplTest, UnaryExpression_Bang) {
ParserImpl p{"!1"}; auto p = parser("!1");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryOp()); ASSERT_TRUE(e->IsUnaryOp());
@ -93,17 +92,17 @@ TEST_F(ParserImplTest, UnaryExpression_Bang) {
} }
TEST_F(ParserImplTest, UnaryExpression_Bang_InvalidRHS) { TEST_F(ParserImplTest, UnaryExpression_Bang_InvalidRHS) {
ParserImpl p{"!if (a) {}"}; auto p = parser("!if (a) {}");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:2: unable to parse right side of ! expression"); EXPECT_EQ(p->error(), "1:2: unable to parse right side of ! expression");
} }
TEST_F(ParserImplTest, UnaryExpression_Any) { TEST_F(ParserImplTest, UnaryExpression_Any) {
ParserImpl p{"any(a)"}; auto p = parser("any(a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryMethod()); ASSERT_TRUE(e->IsUnaryMethod());
@ -117,41 +116,41 @@ TEST_F(ParserImplTest, UnaryExpression_Any) {
} }
TEST_F(ParserImplTest, UnaryExpression_Any_MissingParenLeft) { TEST_F(ParserImplTest, UnaryExpression_Any_MissingParenLeft) {
ParserImpl p{"any a)"}; auto p = parser("any a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:5: missing ( for method call"); EXPECT_EQ(p->error(), "1:5: missing ( for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_Any_MissingParenRight) { TEST_F(ParserImplTest, UnaryExpression_Any_MissingParenRight) {
ParserImpl p{"any(a"}; auto p = parser("any(a");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:6: missing ) for method call"); EXPECT_EQ(p->error(), "1:6: missing ) for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_Any_MissingIdentifier) { TEST_F(ParserImplTest, UnaryExpression_Any_MissingIdentifier) {
ParserImpl p{"any()"}; auto p = parser("any()");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:5: missing identifier for method call"); EXPECT_EQ(p->error(), "1:5: missing identifier for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_Any_InvalidIdentifier) { TEST_F(ParserImplTest, UnaryExpression_Any_InvalidIdentifier) {
ParserImpl p{"any(123)"}; auto p = parser("any(123)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:5: missing identifier for method call"); EXPECT_EQ(p->error(), "1:5: missing identifier for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_All) { TEST_F(ParserImplTest, UnaryExpression_All) {
ParserImpl p{"all(a)"}; auto p = parser("all(a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryMethod()); ASSERT_TRUE(e->IsUnaryMethod());
@ -165,41 +164,41 @@ TEST_F(ParserImplTest, UnaryExpression_All) {
} }
TEST_F(ParserImplTest, UnaryExpression_All_MissingParenLeft) { TEST_F(ParserImplTest, UnaryExpression_All_MissingParenLeft) {
ParserImpl p{"all a)"}; auto p = parser("all a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:5: missing ( for method call"); EXPECT_EQ(p->error(), "1:5: missing ( for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_All_MissingParenRight) { TEST_F(ParserImplTest, UnaryExpression_All_MissingParenRight) {
ParserImpl p{"all(a"}; auto p = parser("all(a");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:6: missing ) for method call"); EXPECT_EQ(p->error(), "1:6: missing ) for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_All_MissingIdentifier) { TEST_F(ParserImplTest, UnaryExpression_All_MissingIdentifier) {
ParserImpl p{"all()"}; auto p = parser("all()");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:5: missing identifier for method call"); EXPECT_EQ(p->error(), "1:5: missing identifier for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_All_InvalidIdentifier) { TEST_F(ParserImplTest, UnaryExpression_All_InvalidIdentifier) {
ParserImpl p{"all(123)"}; auto p = parser("all(123)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:5: missing identifier for method call"); EXPECT_EQ(p->error(), "1:5: missing identifier for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_IsNan) { TEST_F(ParserImplTest, UnaryExpression_IsNan) {
ParserImpl p{"is_nan(a)"}; auto p = parser("is_nan(a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryMethod()); ASSERT_TRUE(e->IsUnaryMethod());
@ -213,41 +212,41 @@ TEST_F(ParserImplTest, UnaryExpression_IsNan) {
} }
TEST_F(ParserImplTest, UnaryExpression_IsNan_MissingParenLeft) { TEST_F(ParserImplTest, UnaryExpression_IsNan_MissingParenLeft) {
ParserImpl p{"is_nan a)"}; auto p = parser("is_nan a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: missing ( for method call"); EXPECT_EQ(p->error(), "1:8: missing ( for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_IsNan_MissingParenRight) { TEST_F(ParserImplTest, UnaryExpression_IsNan_MissingParenRight) {
ParserImpl p{"is_nan(a"}; auto p = parser("is_nan(a");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:9: missing ) for method call"); EXPECT_EQ(p->error(), "1:9: missing ) for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_IsNan_MissingIdentifier) { TEST_F(ParserImplTest, UnaryExpression_IsNan_MissingIdentifier) {
ParserImpl p{"is_nan()"}; auto p = parser("is_nan()");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: missing identifier for method call"); EXPECT_EQ(p->error(), "1:8: missing identifier for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_IsNan_InvalidIdentifier) { TEST_F(ParserImplTest, UnaryExpression_IsNan_InvalidIdentifier) {
ParserImpl p{"is_nan(123)"}; auto p = parser("is_nan(123)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: missing identifier for method call"); EXPECT_EQ(p->error(), "1:8: missing identifier for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_IsInf) { TEST_F(ParserImplTest, UnaryExpression_IsInf) {
ParserImpl p{"is_inf(a)"}; auto p = parser("is_inf(a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryMethod()); ASSERT_TRUE(e->IsUnaryMethod());
@ -261,41 +260,41 @@ TEST_F(ParserImplTest, UnaryExpression_IsInf) {
} }
TEST_F(ParserImplTest, UnaryExpression_IsInf_MissingParenLeft) { TEST_F(ParserImplTest, UnaryExpression_IsInf_MissingParenLeft) {
ParserImpl p{"is_inf a)"}; auto p = parser("is_inf a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: missing ( for method call"); EXPECT_EQ(p->error(), "1:8: missing ( for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_IsInf_MissingParenRight) { TEST_F(ParserImplTest, UnaryExpression_IsInf_MissingParenRight) {
ParserImpl p{"is_inf(a"}; auto p = parser("is_inf(a");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:9: missing ) for method call"); EXPECT_EQ(p->error(), "1:9: missing ) for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_IsInf_MissingIdentifier) { TEST_F(ParserImplTest, UnaryExpression_IsInf_MissingIdentifier) {
ParserImpl p{"is_inf()"}; auto p = parser("is_inf()");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: missing identifier for method call"); EXPECT_EQ(p->error(), "1:8: missing identifier for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_IsInf_InvalidIdentifier) { TEST_F(ParserImplTest, UnaryExpression_IsInf_InvalidIdentifier) {
ParserImpl p{"is_inf(123)"}; auto p = parser("is_inf(123)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: missing identifier for method call"); EXPECT_EQ(p->error(), "1:8: missing identifier for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_IsFinite) { TEST_F(ParserImplTest, UnaryExpression_IsFinite) {
ParserImpl p{"is_finite(a)"}; auto p = parser("is_finite(a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryMethod()); ASSERT_TRUE(e->IsUnaryMethod());
@ -309,41 +308,41 @@ TEST_F(ParserImplTest, UnaryExpression_IsFinite) {
} }
TEST_F(ParserImplTest, UnaryExpression_IsFinite_MissingParenLeft) { TEST_F(ParserImplTest, UnaryExpression_IsFinite_MissingParenLeft) {
ParserImpl p{"is_finite a)"}; auto p = parser("is_finite a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:11: missing ( for method call"); EXPECT_EQ(p->error(), "1:11: missing ( for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_IsFinite_MissingParenRight) { TEST_F(ParserImplTest, UnaryExpression_IsFinite_MissingParenRight) {
ParserImpl p{"is_finite(a"}; auto p = parser("is_finite(a");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:12: missing ) for method call"); EXPECT_EQ(p->error(), "1:12: missing ) for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_IsFinite_MissingIdentifier) { TEST_F(ParserImplTest, UnaryExpression_IsFinite_MissingIdentifier) {
ParserImpl p{"is_finite()"}; auto p = parser("is_finite()");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:11: missing identifier for method call"); EXPECT_EQ(p->error(), "1:11: missing identifier for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_IsFinite_InvalidIdentifier) { TEST_F(ParserImplTest, UnaryExpression_IsFinite_InvalidIdentifier) {
ParserImpl p{"is_finite(123)"}; auto p = parser("is_finite(123)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:11: missing identifier for method call"); EXPECT_EQ(p->error(), "1:11: missing identifier for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_IsNormal) { TEST_F(ParserImplTest, UnaryExpression_IsNormal) {
ParserImpl p{"is_normal(a)"}; auto p = parser("is_normal(a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryMethod()); ASSERT_TRUE(e->IsUnaryMethod());
@ -357,41 +356,41 @@ TEST_F(ParserImplTest, UnaryExpression_IsNormal) {
} }
TEST_F(ParserImplTest, UnaryExpression_IsNormal_MissingParenLeft) { TEST_F(ParserImplTest, UnaryExpression_IsNormal_MissingParenLeft) {
ParserImpl p{"is_normal a)"}; auto p = parser("is_normal a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:11: missing ( for method call"); EXPECT_EQ(p->error(), "1:11: missing ( for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_IsNormal_MissingParenRight) { TEST_F(ParserImplTest, UnaryExpression_IsNormal_MissingParenRight) {
ParserImpl p{"is_normal(a"}; auto p = parser("is_normal(a");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:12: missing ) for method call"); EXPECT_EQ(p->error(), "1:12: missing ) for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_IsNormal_MissingIdentifier) { TEST_F(ParserImplTest, UnaryExpression_IsNormal_MissingIdentifier) {
ParserImpl p{"is_normal()"}; auto p = parser("is_normal()");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:11: missing identifier for method call"); EXPECT_EQ(p->error(), "1:11: missing identifier for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_IsNormal_InvalidIdentifier) { TEST_F(ParserImplTest, UnaryExpression_IsNormal_InvalidIdentifier) {
ParserImpl p{"is_normal(123)"}; auto p = parser("is_normal(123)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:11: missing identifier for method call"); EXPECT_EQ(p->error(), "1:11: missing identifier for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_Dot) { TEST_F(ParserImplTest, UnaryExpression_Dot) {
ParserImpl p{"dot(a, b)"}; auto p = parser("dot(a, b)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryMethod()); ASSERT_TRUE(e->IsUnaryMethod());
@ -410,65 +409,65 @@ TEST_F(ParserImplTest, UnaryExpression_Dot) {
} }
TEST_F(ParserImplTest, UnaryExpression_Dot_MissingParenLeft) { TEST_F(ParserImplTest, UnaryExpression_Dot_MissingParenLeft) {
ParserImpl p{"dot a, b)"}; auto p = parser("dot a, b)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:5: missing ( for method call"); EXPECT_EQ(p->error(), "1:5: missing ( for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_Dot_MissingParenRight) { TEST_F(ParserImplTest, UnaryExpression_Dot_MissingParenRight) {
ParserImpl p{"dot(a, b"}; auto p = parser("dot(a, b");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:9: missing ) for method call"); EXPECT_EQ(p->error(), "1:9: missing ) for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_Dot_MissingFirstIdentifier) { TEST_F(ParserImplTest, UnaryExpression_Dot_MissingFirstIdentifier) {
ParserImpl p{"dot(, a)"}; auto p = parser("dot(, a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:5: missing identifier for method call"); EXPECT_EQ(p->error(), "1:5: missing identifier for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_Dot_MissingSecondIdentifier) { TEST_F(ParserImplTest, UnaryExpression_Dot_MissingSecondIdentifier) {
ParserImpl p{"dot(a, )"}; auto p = parser("dot(a, )");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: missing identifier for method call"); EXPECT_EQ(p->error(), "1:8: missing identifier for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_Dot_MissingComma) { TEST_F(ParserImplTest, UnaryExpression_Dot_MissingComma) {
ParserImpl p{"dot(a b)"}; auto p = parser("dot(a b)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:7: missing , for method call"); EXPECT_EQ(p->error(), "1:7: missing , for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_Dot_InvalidFirstIdentifier) { TEST_F(ParserImplTest, UnaryExpression_Dot_InvalidFirstIdentifier) {
ParserImpl p{"dot(123, b)"}; auto p = parser("dot(123, b)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:5: missing identifier for method call"); EXPECT_EQ(p->error(), "1:5: missing identifier for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_Dot_InvalidSecondIdentifier) { TEST_F(ParserImplTest, UnaryExpression_Dot_InvalidSecondIdentifier) {
ParserImpl p{"dot(a, 123)"}; auto p = parser("dot(a, 123)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: missing identifier for method call"); EXPECT_EQ(p->error(), "1:8: missing identifier for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_OuterProduct) { TEST_F(ParserImplTest, UnaryExpression_OuterProduct) {
ParserImpl p{"outer_product(a, b)"}; auto p = parser("outer_product(a, b)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryMethod()); ASSERT_TRUE(e->IsUnaryMethod());
@ -487,65 +486,65 @@ TEST_F(ParserImplTest, UnaryExpression_OuterProduct) {
} }
TEST_F(ParserImplTest, UnaryExpression_OuterProduct_MissingParenLeft) { TEST_F(ParserImplTest, UnaryExpression_OuterProduct_MissingParenLeft) {
ParserImpl p{"outer_product a, b)"}; auto p = parser("outer_product a, b)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:15: missing ( for method call"); EXPECT_EQ(p->error(), "1:15: missing ( for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_OuterProduct_MissingParenRight) { TEST_F(ParserImplTest, UnaryExpression_OuterProduct_MissingParenRight) {
ParserImpl p{"outer_product(a, b"}; auto p = parser("outer_product(a, b");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:19: missing ) for method call"); EXPECT_EQ(p->error(), "1:19: missing ) for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_OuterProduct_MissingFirstIdentifier) { TEST_F(ParserImplTest, UnaryExpression_OuterProduct_MissingFirstIdentifier) {
ParserImpl p{"outer_product(, b)"}; auto p = parser("outer_product(, b)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:15: missing identifier for method call"); EXPECT_EQ(p->error(), "1:15: missing identifier for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_OuterProduct_MissingSecondIdentifier) { TEST_F(ParserImplTest, UnaryExpression_OuterProduct_MissingSecondIdentifier) {
ParserImpl p{"outer_product(a, )"}; auto p = parser("outer_product(a, )");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:18: missing identifier for method call"); EXPECT_EQ(p->error(), "1:18: missing identifier for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_OuterProduct_MissingComma) { TEST_F(ParserImplTest, UnaryExpression_OuterProduct_MissingComma) {
ParserImpl p{"outer_product(a b)"}; auto p = parser("outer_product(a b)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:17: missing , for method call"); EXPECT_EQ(p->error(), "1:17: missing , for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_OuterProduct_InvalidFirstIdentifier) { TEST_F(ParserImplTest, UnaryExpression_OuterProduct_InvalidFirstIdentifier) {
ParserImpl p{"outer_product(123, b)"}; auto p = parser("outer_product(123, b)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:15: missing identifier for method call"); EXPECT_EQ(p->error(), "1:15: missing identifier for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_OuterProduct_InvalidSecondIdentifier) { TEST_F(ParserImplTest, UnaryExpression_OuterProduct_InvalidSecondIdentifier) {
ParserImpl p{"outer_product(a, 123)"}; auto p = parser("outer_product(a, 123)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:18: missing identifier for method call"); EXPECT_EQ(p->error(), "1:18: missing identifier for method call");
} }
TEST_F(ParserImplTest, UnaryExpression_Dpdx_NoModifier) { TEST_F(ParserImplTest, UnaryExpression_Dpdx_NoModifier) {
ParserImpl p{"dpdx(a)"}; auto p = parser("dpdx(a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryDerivative()); ASSERT_TRUE(e->IsUnaryDerivative());
@ -561,9 +560,9 @@ TEST_F(ParserImplTest, UnaryExpression_Dpdx_NoModifier) {
} }
TEST_F(ParserImplTest, UnaryExpression_Dpdx_WithModifier) { TEST_F(ParserImplTest, UnaryExpression_Dpdx_WithModifier) {
ParserImpl p{"dpdx<coarse>(a)"}; auto p = parser("dpdx<coarse>(a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryDerivative()); ASSERT_TRUE(e->IsUnaryDerivative());
@ -579,73 +578,73 @@ TEST_F(ParserImplTest, UnaryExpression_Dpdx_WithModifier) {
} }
TEST_F(ParserImplTest, UnaryExpression_Dpdx_MissingLessThan) { TEST_F(ParserImplTest, UnaryExpression_Dpdx_MissingLessThan) {
ParserImpl p{"dpdx coarse>(a)"}; auto p = parser("dpdx coarse>(a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:6: missing ( for derivative method"); EXPECT_EQ(p->error(), "1:6: missing ( for derivative method");
} }
TEST_F(ParserImplTest, UnaryExpression_Dpdx_InvalidModifier) { TEST_F(ParserImplTest, UnaryExpression_Dpdx_InvalidModifier) {
ParserImpl p{"dpdx<invalid>(a)"}; auto p = parser("dpdx<invalid>(a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:6: unable to parse derivative modifier"); EXPECT_EQ(p->error(), "1:6: unable to parse derivative modifier");
} }
TEST_F(ParserImplTest, UnaryExpression_Dpdx_EmptyModifer) { TEST_F(ParserImplTest, UnaryExpression_Dpdx_EmptyModifer) {
ParserImpl p{"dpdx coarse>(a)"}; auto p = parser("dpdx coarse>(a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:6: missing ( for derivative method"); EXPECT_EQ(p->error(), "1:6: missing ( for derivative method");
} }
TEST_F(ParserImplTest, UnaryExpression_Dpdx_MissingGreaterThan) { TEST_F(ParserImplTest, UnaryExpression_Dpdx_MissingGreaterThan) {
ParserImpl p{"dpdx<coarse (a)"}; auto p = parser("dpdx<coarse (a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:13: missing > for derivative modifier"); EXPECT_EQ(p->error(), "1:13: missing > for derivative modifier");
} }
TEST_F(ParserImplTest, UnaryExpression_Dpdx_MisisngLeftParen) { TEST_F(ParserImplTest, UnaryExpression_Dpdx_MisisngLeftParen) {
ParserImpl p{"dpdx<coarse>a)"}; auto p = parser("dpdx<coarse>a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:13: missing ( for derivative method"); EXPECT_EQ(p->error(), "1:13: missing ( for derivative method");
} }
TEST_F(ParserImplTest, UnaryExpression_Dpdx_MissingRightParen) { TEST_F(ParserImplTest, UnaryExpression_Dpdx_MissingRightParen) {
ParserImpl p{"dpdx<coarse>(a"}; auto p = parser("dpdx<coarse>(a");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:15: missing ) for derivative method"); EXPECT_EQ(p->error(), "1:15: missing ) for derivative method");
} }
TEST_F(ParserImplTest, UnaryExpression_Dpdx_MissingIdentifier) { TEST_F(ParserImplTest, UnaryExpression_Dpdx_MissingIdentifier) {
ParserImpl p{"dpdx<coarse>()"}; auto p = parser("dpdx<coarse>()");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:14: missing identifier for derivative method"); EXPECT_EQ(p->error(), "1:14: missing identifier for derivative method");
} }
TEST_F(ParserImplTest, UnaryExpression_Dpdx_InvalidIdentifeir) { TEST_F(ParserImplTest, UnaryExpression_Dpdx_InvalidIdentifeir) {
ParserImpl p{"dpdx<coarse>(12345)"}; auto p = parser("dpdx<coarse>(12345)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:14: missing identifier for derivative method"); EXPECT_EQ(p->error(), "1:14: missing identifier for derivative method");
} }
TEST_F(ParserImplTest, UnaryExpression_Dpdy_NoModifier) { TEST_F(ParserImplTest, UnaryExpression_Dpdy_NoModifier) {
ParserImpl p{"dpdy(a)"}; auto p = parser("dpdy(a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryDerivative()); ASSERT_TRUE(e->IsUnaryDerivative());
@ -661,9 +660,9 @@ TEST_F(ParserImplTest, UnaryExpression_Dpdy_NoModifier) {
} }
TEST_F(ParserImplTest, UnaryExpression_Dpdy_WithModifier) { TEST_F(ParserImplTest, UnaryExpression_Dpdy_WithModifier) {
ParserImpl p{"dpdy<fine>(a)"}; auto p = parser("dpdy<fine>(a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryDerivative()); ASSERT_TRUE(e->IsUnaryDerivative());
@ -679,73 +678,73 @@ TEST_F(ParserImplTest, UnaryExpression_Dpdy_WithModifier) {
} }
TEST_F(ParserImplTest, UnaryExpression_Dpdy_MissingLessThan) { TEST_F(ParserImplTest, UnaryExpression_Dpdy_MissingLessThan) {
ParserImpl p{"dpdy coarse>(a)"}; auto p = parser("dpdy coarse>(a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:6: missing ( for derivative method"); EXPECT_EQ(p->error(), "1:6: missing ( for derivative method");
} }
TEST_F(ParserImplTest, UnaryExpression_Dpdy_InvalidModifier) { TEST_F(ParserImplTest, UnaryExpression_Dpdy_InvalidModifier) {
ParserImpl p{"dpdy<invalid>(a)"}; auto p = parser("dpdy<invalid>(a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:6: unable to parse derivative modifier"); EXPECT_EQ(p->error(), "1:6: unable to parse derivative modifier");
} }
TEST_F(ParserImplTest, UnaryExpression_Dpdy_EmptyModifer) { TEST_F(ParserImplTest, UnaryExpression_Dpdy_EmptyModifer) {
ParserImpl p{"dpdy coarse>(a)"}; auto p = parser("dpdy coarse>(a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:6: missing ( for derivative method"); EXPECT_EQ(p->error(), "1:6: missing ( for derivative method");
} }
TEST_F(ParserImplTest, UnaryExpression_Dpdy_MissingGreaterThan) { TEST_F(ParserImplTest, UnaryExpression_Dpdy_MissingGreaterThan) {
ParserImpl p{"dpdy<coarse (a)"}; auto p = parser("dpdy<coarse (a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:13: missing > for derivative modifier"); EXPECT_EQ(p->error(), "1:13: missing > for derivative modifier");
} }
TEST_F(ParserImplTest, UnaryExpression_Dpdy_MisisngLeftParen) { TEST_F(ParserImplTest, UnaryExpression_Dpdy_MisisngLeftParen) {
ParserImpl p{"dpdy<coarse>a)"}; auto p = parser("dpdy<coarse>a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:13: missing ( for derivative method"); EXPECT_EQ(p->error(), "1:13: missing ( for derivative method");
} }
TEST_F(ParserImplTest, UnaryExpression_Dpdy_MissingRightParen) { TEST_F(ParserImplTest, UnaryExpression_Dpdy_MissingRightParen) {
ParserImpl p{"dpdy<coarse>(a"}; auto p = parser("dpdy<coarse>(a");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:15: missing ) for derivative method"); EXPECT_EQ(p->error(), "1:15: missing ) for derivative method");
} }
TEST_F(ParserImplTest, UnaryExpression_Dpdy_MissingIdentifier) { TEST_F(ParserImplTest, UnaryExpression_Dpdy_MissingIdentifier) {
ParserImpl p{"dpdy<coarse>()"}; auto p = parser("dpdy<coarse>()");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:14: missing identifier for derivative method"); EXPECT_EQ(p->error(), "1:14: missing identifier for derivative method");
} }
TEST_F(ParserImplTest, UnaryExpression_Dpdy_InvalidIdentifeir) { TEST_F(ParserImplTest, UnaryExpression_Dpdy_InvalidIdentifeir) {
ParserImpl p{"dpdy<coarse>(12345)"}; auto p = parser("dpdy<coarse>(12345)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:14: missing identifier for derivative method"); EXPECT_EQ(p->error(), "1:14: missing identifier for derivative method");
} }
TEST_F(ParserImplTest, UnaryExpression_Fwidth_NoModifier) { TEST_F(ParserImplTest, UnaryExpression_Fwidth_NoModifier) {
ParserImpl p{"fwidth(a)"}; auto p = parser("fwidth(a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryDerivative()); ASSERT_TRUE(e->IsUnaryDerivative());
@ -761,9 +760,9 @@ TEST_F(ParserImplTest, UnaryExpression_Fwidth_NoModifier) {
} }
TEST_F(ParserImplTest, UnaryExpression_Fwidth_WithModifier) { TEST_F(ParserImplTest, UnaryExpression_Fwidth_WithModifier) {
ParserImpl p{"fwidth<coarse>(a)"}; auto p = parser("fwidth<coarse>(a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryDerivative()); ASSERT_TRUE(e->IsUnaryDerivative());
@ -779,67 +778,67 @@ TEST_F(ParserImplTest, UnaryExpression_Fwidth_WithModifier) {
} }
TEST_F(ParserImplTest, UnaryExpression_Fwidth_MissingLessThan) { TEST_F(ParserImplTest, UnaryExpression_Fwidth_MissingLessThan) {
ParserImpl p{"fwidth coarse>(a)"}; auto p = parser("fwidth coarse>(a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: missing ( for derivative method"); EXPECT_EQ(p->error(), "1:8: missing ( for derivative method");
} }
TEST_F(ParserImplTest, UnaryExpression_Fwidth_InvalidModifier) { TEST_F(ParserImplTest, UnaryExpression_Fwidth_InvalidModifier) {
ParserImpl p{"fwidth<invalid>(a)"}; auto p = parser("fwidth<invalid>(a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: unable to parse derivative modifier"); EXPECT_EQ(p->error(), "1:8: unable to parse derivative modifier");
} }
TEST_F(ParserImplTest, UnaryExpression_Fwidth_EmptyModifer) { TEST_F(ParserImplTest, UnaryExpression_Fwidth_EmptyModifer) {
ParserImpl p{"fwidth coarse>(a)"}; auto p = parser("fwidth coarse>(a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: missing ( for derivative method"); EXPECT_EQ(p->error(), "1:8: missing ( for derivative method");
} }
TEST_F(ParserImplTest, UnaryExpression_Fwidth_MissingGreaterThan) { TEST_F(ParserImplTest, UnaryExpression_Fwidth_MissingGreaterThan) {
ParserImpl p{"fwidth<coarse (a)"}; auto p = parser("fwidth<coarse (a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:15: missing > for derivative modifier"); EXPECT_EQ(p->error(), "1:15: missing > for derivative modifier");
} }
TEST_F(ParserImplTest, UnaryExpression_Fwidth_MisisngLeftParen) { TEST_F(ParserImplTest, UnaryExpression_Fwidth_MisisngLeftParen) {
ParserImpl p{"fwidth<coarse>a)"}; auto p = parser("fwidth<coarse>a)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:15: missing ( for derivative method"); EXPECT_EQ(p->error(), "1:15: missing ( for derivative method");
} }
TEST_F(ParserImplTest, UnaryExpression_Fwidth_MissingRightParen) { TEST_F(ParserImplTest, UnaryExpression_Fwidth_MissingRightParen) {
ParserImpl p{"fwidth<coarse>(a"}; auto p = parser("fwidth<coarse>(a");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:17: missing ) for derivative method"); EXPECT_EQ(p->error(), "1:17: missing ) for derivative method");
} }
TEST_F(ParserImplTest, UnaryExpression_Fwidth_MissingIdentifier) { TEST_F(ParserImplTest, UnaryExpression_Fwidth_MissingIdentifier) {
ParserImpl p{"fwidth<coarse>()"}; auto p = parser("fwidth<coarse>()");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:16: missing identifier for derivative method"); EXPECT_EQ(p->error(), "1:16: missing identifier for derivative method");
} }
TEST_F(ParserImplTest, UnaryExpression_Fwidht_InvalidIdentifeir) { TEST_F(ParserImplTest, UnaryExpression_Fwidht_InvalidIdentifeir) {
ParserImpl p{"fwidth<coarse>(12345)"}; auto p = parser("fwidth<coarse>(12345)");
auto e = p.unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:16: missing identifier for derivative method"); EXPECT_EQ(p->error(), "1:16: missing identifier for derivative method");
} }
} // namespace wgsl } // namespace wgsl
} // namespace reader } // namespace reader

View File

@ -14,17 +14,16 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, UnlessStmt) { TEST_F(ParserImplTest, UnlessStmt) {
ParserImpl p{"unless (a) { kill; }"}; auto p = parser("unless (a) { kill; }");
auto e = p.unless_stmt(); auto e = p->unless_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnless()); ASSERT_TRUE(e->IsUnless());
ASSERT_NE(e->condition(), nullptr); ASSERT_NE(e->condition(), nullptr);
@ -34,27 +33,27 @@ TEST_F(ParserImplTest, UnlessStmt) {
} }
TEST_F(ParserImplTest, UnlessStmt_InvalidCondition) { TEST_F(ParserImplTest, UnlessStmt_InvalidCondition) {
ParserImpl p{"unless(if(a){}) {}"}; auto p = parser("unless(if(a){}) {}");
auto e = p.unless_stmt(); auto e = p->unless_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: unable to parse expression"); EXPECT_EQ(p->error(), "1:8: unable to parse expression");
} }
TEST_F(ParserImplTest, UnlessStmt_EmptyCondition) { TEST_F(ParserImplTest, UnlessStmt_EmptyCondition) {
ParserImpl p{"unless() {}"}; auto p = parser("unless() {}");
auto e = p.unless_stmt(); auto e = p->unless_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: unable to parse expression"); EXPECT_EQ(p->error(), "1:8: unable to parse expression");
} }
TEST_F(ParserImplTest, UnlessStmt_InvalidBody) { TEST_F(ParserImplTest, UnlessStmt_InvalidBody) {
ParserImpl p{"unless(a + 2 - 5 == true) { kill }"}; auto p = parser("unless(a + 2 - 5 == true) { kill }");
auto e = p.unless_stmt(); auto e = p->unless_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:34: missing ;"); EXPECT_EQ(p->error(), "1:34: missing ;");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -15,17 +15,16 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/ast/variable.h" #include "src/ast/variable.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, VariableDecl_Parses) { TEST_F(ParserImplTest, VariableDecl_Parses) {
ParserImpl p{"var my_var : f32"}; auto p = parser("var my_var : f32");
auto var = p.variable_decl(); auto var = p->variable_decl();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_NE(var, nullptr); ASSERT_NE(var, nullptr);
ASSERT_EQ(var->name(), "my_var"); ASSERT_EQ(var->name(), "my_var");
ASSERT_NE(var->type(), nullptr); ASSERT_NE(var->type(), nullptr);
@ -35,27 +34,27 @@ TEST_F(ParserImplTest, VariableDecl_Parses) {
} }
TEST_F(ParserImplTest, VariableDecl_MissingVar) { TEST_F(ParserImplTest, VariableDecl_MissingVar) {
ParserImpl p{"my_var : f32"}; auto p = parser("my_var : f32");
auto v = p.variable_decl(); auto v = p->variable_decl();
ASSERT_EQ(v, nullptr); ASSERT_EQ(v, nullptr);
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
auto t = p.next(); auto t = p->next();
ASSERT_TRUE(t.IsIdentifier()); ASSERT_TRUE(t.IsIdentifier());
} }
TEST_F(ParserImplTest, VariableDecl_InvalidIdentDecl) { TEST_F(ParserImplTest, VariableDecl_InvalidIdentDecl) {
ParserImpl p{"var my_var f32"}; auto p = parser("var my_var f32");
auto v = p.variable_decl(); auto v = p->variable_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(v, nullptr); ASSERT_EQ(v, nullptr);
ASSERT_EQ(p.error(), "1:12: missing : for identifier declaration"); ASSERT_EQ(p->error(), "1:12: missing : for identifier declaration");
} }
TEST_F(ParserImplTest, VariableDecl_WithStorageClass) { TEST_F(ParserImplTest, VariableDecl_WithStorageClass) {
ParserImpl p{"var<private> my_var : f32"}; auto p = parser("var<private> my_var : f32");
auto v = p.variable_decl(); auto v = p->variable_decl();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_NE(v, nullptr); ASSERT_NE(v, nullptr);
EXPECT_EQ(v->name(), "my_var"); EXPECT_EQ(v->name(), "my_var");
EXPECT_TRUE(v->type()->IsF32()); EXPECT_TRUE(v->type()->IsF32());
@ -63,11 +62,11 @@ TEST_F(ParserImplTest, VariableDecl_WithStorageClass) {
} }
TEST_F(ParserImplTest, VariableDecl_InvalidStorageClass) { TEST_F(ParserImplTest, VariableDecl_InvalidStorageClass) {
ParserImpl p{"var<unknown> my_var : f32"}; auto p = parser("var<unknown> my_var : f32");
auto v = p.variable_decl(); auto v = p->variable_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(v, nullptr); ASSERT_EQ(v, nullptr);
EXPECT_EQ(p.error(), "1:5: invalid storage class for variable decoration"); EXPECT_EQ(p->error(), "1:5: invalid storage class for variable decoration");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -16,17 +16,16 @@
#include "src/ast/builtin_decoration.h" #include "src/ast/builtin_decoration.h"
#include "src/ast/location_decoration.h" #include "src/ast/location_decoration.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, VariableDecorationList_Parses) { TEST_F(ParserImplTest, VariableDecorationList_Parses) {
ParserImpl p{R"([[location 4, builtin position]])"}; auto p = parser(R"([[location 4, builtin position]])");
auto decos = p.variable_decoration_list(); auto decos = p->variable_decoration_list();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_EQ(decos.size(), 2); ASSERT_EQ(decos.size(), 2);
ASSERT_TRUE(decos[0]->IsLocation()); ASSERT_TRUE(decos[0]->IsLocation());
EXPECT_EQ(decos[0]->AsLocation()->value(), 4); EXPECT_EQ(decos[0]->AsLocation()->value(), 4);
@ -35,45 +34,45 @@ TEST_F(ParserImplTest, VariableDecorationList_Parses) {
} }
TEST_F(ParserImplTest, VariableDecorationList_Empty) { TEST_F(ParserImplTest, VariableDecorationList_Empty) {
ParserImpl p{R"([[]])"}; auto p = parser(R"([[]])");
auto decos = p.variable_decoration_list(); auto decos = p->variable_decoration_list();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:3: empty variable decoration list"); ASSERT_EQ(p->error(), "1:3: empty variable decoration list");
} }
TEST_F(ParserImplTest, VariableDecorationList_Invalid) { TEST_F(ParserImplTest, VariableDecorationList_Invalid) {
ParserImpl p{R"([[invalid]])"}; auto p = parser(R"([[invalid]])");
auto decos = p.variable_decoration_list(); auto decos = p->variable_decoration_list();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:3: missing variable decoration for decoration list"); ASSERT_EQ(p->error(), "1:3: missing variable decoration for decoration list");
} }
TEST_F(ParserImplTest, VariableDecorationList_ExtraComma) { TEST_F(ParserImplTest, VariableDecorationList_ExtraComma) {
ParserImpl p{R"([[builtin position, ]])"}; auto p = parser(R"([[builtin position, ]])");
auto decos = p.variable_decoration_list(); auto decos = p->variable_decoration_list();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:21: missing variable decoration after comma"); ASSERT_EQ(p->error(), "1:21: missing variable decoration after comma");
} }
TEST_F(ParserImplTest, VariableDecorationList_MissingComma) { TEST_F(ParserImplTest, VariableDecorationList_MissingComma) {
ParserImpl p{R"([[binding 4 location 5]])"}; auto p = parser(R"([[binding 4 location 5]])");
auto decos = p.variable_decoration_list(); auto decos = p->variable_decoration_list();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:13: missing comma in variable decoration list"); ASSERT_EQ(p->error(), "1:13: missing comma in variable decoration list");
} }
TEST_F(ParserImplTest, VariableDecorationList_BadDecoration) { TEST_F(ParserImplTest, VariableDecorationList_BadDecoration) {
ParserImpl p{R"([[location bad]])"}; auto p = parser(R"([[location bad]])");
auto decos = p.variable_decoration_list(); auto decos = p->variable_decoration_list();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:12: invalid value for location decoration"); ASSERT_EQ(p->error(), "1:12: invalid value for location decoration");
} }
TEST_F(ParserImplTest, VariableDecorationList_InvalidBuiltin) { TEST_F(ParserImplTest, VariableDecorationList_InvalidBuiltin) {
ParserImpl p{"[[builtin invalid]]"}; auto p = parser("[[builtin invalid]]");
auto decos = p.variable_decoration_list(); auto decos = p->variable_decoration_list();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:11: invalid value for builtin decoration"); ASSERT_EQ(p->error(), "1:11: invalid value for builtin decoration");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -18,18 +18,17 @@
#include "src/ast/location_decoration.h" #include "src/ast/location_decoration.h"
#include "src/ast/set_decoration.h" #include "src/ast/set_decoration.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, VariableDecoration_Location) { TEST_F(ParserImplTest, VariableDecoration_Location) {
ParserImpl p{"location 4"}; auto p = parser("location 4");
auto deco = p.variable_decoration(); auto deco = p->variable_decoration();
ASSERT_NE(deco, nullptr); ASSERT_NE(deco, nullptr);
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_TRUE(deco->IsLocation()); ASSERT_TRUE(deco->IsLocation());
auto loc = deco->AsLocation(); auto loc = deco->AsLocation();
@ -37,25 +36,25 @@ TEST_F(ParserImplTest, VariableDecoration_Location) {
} }
TEST_F(ParserImplTest, VariableDecoration_Location_MissingValue) { TEST_F(ParserImplTest, VariableDecoration_Location_MissingValue) {
ParserImpl p{"location"}; auto p = parser("location");
auto deco = p.variable_decoration(); auto deco = p->variable_decoration();
ASSERT_EQ(deco, nullptr); ASSERT_EQ(deco, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:9: invalid value for location decoration"); EXPECT_EQ(p->error(), "1:9: invalid value for location decoration");
} }
TEST_F(ParserImplTest, VariableDecoration_Location_MissingInvalid) { TEST_F(ParserImplTest, VariableDecoration_Location_MissingInvalid) {
ParserImpl p{"location nan"}; auto p = parser("location nan");
auto deco = p.variable_decoration(); auto deco = p->variable_decoration();
ASSERT_EQ(deco, nullptr); ASSERT_EQ(deco, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:10: invalid value for location decoration"); EXPECT_EQ(p->error(), "1:10: invalid value for location decoration");
} }
TEST_F(ParserImplTest, VariableDecoration_Builtin) { TEST_F(ParserImplTest, VariableDecoration_Builtin) {
ParserImpl p{"builtin frag_depth"}; auto p = parser("builtin frag_depth");
auto deco = p.variable_decoration(); auto deco = p->variable_decoration();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_NE(deco, nullptr); ASSERT_NE(deco, nullptr);
ASSERT_TRUE(deco->IsBuiltin()); ASSERT_TRUE(deco->IsBuiltin());
@ -64,26 +63,26 @@ TEST_F(ParserImplTest, VariableDecoration_Builtin) {
} }
TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingValue) { TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingValue) {
ParserImpl p{"builtin"}; auto p = parser("builtin");
auto deco = p.variable_decoration(); auto deco = p->variable_decoration();
ASSERT_EQ(deco, nullptr); ASSERT_EQ(deco, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:8: invalid value for builtin decoration"); EXPECT_EQ(p->error(), "1:8: invalid value for builtin decoration");
} }
TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingInvalid) { TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingInvalid) {
ParserImpl p{"builtin 3"}; auto p = parser("builtin 3");
auto deco = p.variable_decoration(); auto deco = p->variable_decoration();
ASSERT_EQ(deco, nullptr); ASSERT_EQ(deco, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:9: invalid value for builtin decoration"); EXPECT_EQ(p->error(), "1:9: invalid value for builtin decoration");
} }
TEST_F(ParserImplTest, VariableDecoration_Binding) { TEST_F(ParserImplTest, VariableDecoration_Binding) {
ParserImpl p{"binding 4"}; auto p = parser("binding 4");
auto deco = p.variable_decoration(); auto deco = p->variable_decoration();
ASSERT_NE(deco, nullptr); ASSERT_NE(deco, nullptr);
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_TRUE(deco->IsBinding()); ASSERT_TRUE(deco->IsBinding());
auto binding = deco->AsBinding(); auto binding = deco->AsBinding();
@ -91,25 +90,25 @@ TEST_F(ParserImplTest, VariableDecoration_Binding) {
} }
TEST_F(ParserImplTest, VariableDecoration_Binding_MissingValue) { TEST_F(ParserImplTest, VariableDecoration_Binding_MissingValue) {
ParserImpl p{"binding"}; auto p = parser("binding");
auto deco = p.variable_decoration(); auto deco = p->variable_decoration();
ASSERT_EQ(deco, nullptr); ASSERT_EQ(deco, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:8: invalid value for binding decoration"); EXPECT_EQ(p->error(), "1:8: invalid value for binding decoration");
} }
TEST_F(ParserImplTest, VariableDecoration_Binding_MissingInvalid) { TEST_F(ParserImplTest, VariableDecoration_Binding_MissingInvalid) {
ParserImpl p{"binding nan"}; auto p = parser("binding nan");
auto deco = p.variable_decoration(); auto deco = p->variable_decoration();
ASSERT_EQ(deco, nullptr); ASSERT_EQ(deco, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:9: invalid value for binding decoration"); EXPECT_EQ(p->error(), "1:9: invalid value for binding decoration");
} }
TEST_F(ParserImplTest, VariableDecoration_set) { TEST_F(ParserImplTest, VariableDecoration_set) {
ParserImpl p{"set 4"}; auto p = parser("set 4");
auto deco = p.variable_decoration(); auto deco = p->variable_decoration();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_NE(deco.get(), nullptr); ASSERT_NE(deco.get(), nullptr);
ASSERT_TRUE(deco->IsSet()); ASSERT_TRUE(deco->IsSet());
@ -118,19 +117,19 @@ TEST_F(ParserImplTest, VariableDecoration_set) {
} }
TEST_F(ParserImplTest, VariableDecoration_Set_MissingValue) { TEST_F(ParserImplTest, VariableDecoration_Set_MissingValue) {
ParserImpl p{"set"}; auto p = parser("set");
auto deco = p.variable_decoration(); auto deco = p->variable_decoration();
ASSERT_EQ(deco, nullptr); ASSERT_EQ(deco, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:4: invalid value for set decoration"); EXPECT_EQ(p->error(), "1:4: invalid value for set decoration");
} }
TEST_F(ParserImplTest, VariableDecoration_Set_MissingInvalid) { TEST_F(ParserImplTest, VariableDecoration_Set_MissingInvalid) {
ParserImpl p{"set nan"}; auto p = parser("set nan");
auto deco = p.variable_decoration(); auto deco = p->variable_decoration();
ASSERT_EQ(deco, nullptr); ASSERT_EQ(deco, nullptr);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p.error(), "1:5: invalid value for set decoration"); EXPECT_EQ(p->error(), "1:5: invalid value for set decoration");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -14,69 +14,68 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, VariableIdentDecl_Parses) { TEST_F(ParserImplTest, VariableIdentDecl_Parses) {
ParserImpl p{"my_var : f32"}; auto p = parser("my_var : f32");
std::string name; std::string name;
ast::type::Type* type; ast::type::Type* type;
std::tie(name, type) = p.variable_ident_decl(); std::tie(name, type) = p->variable_ident_decl();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_EQ(name, "my_var"); ASSERT_EQ(name, "my_var");
ASSERT_NE(type, nullptr); ASSERT_NE(type, nullptr);
ASSERT_TRUE(type->IsF32()); ASSERT_TRUE(type->IsF32());
} }
TEST_F(ParserImplTest, VariableIdentDecl_MissingIdent) { TEST_F(ParserImplTest, VariableIdentDecl_MissingIdent) {
ParserImpl p{": f32"}; auto p = parser(": f32");
std::string name; std::string name;
ast::type::Type* type; ast::type::Type* type;
std::tie(name, type) = p.variable_ident_decl(); std::tie(name, type) = p->variable_ident_decl();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_EQ(name, ""); ASSERT_EQ(name, "");
ASSERT_EQ(type, nullptr); ASSERT_EQ(type, nullptr);
auto t = p.next(); auto t = p->next();
ASSERT_TRUE(t.IsColon()); ASSERT_TRUE(t.IsColon());
} }
TEST_F(ParserImplTest, VariableIdentDecl_MissingColon) { TEST_F(ParserImplTest, VariableIdentDecl_MissingColon) {
ParserImpl p{"my_var f32"}; auto p = parser("my_var f32");
auto r = p.variable_ident_decl(); auto r = p->variable_ident_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:8: missing : for identifier declaration"); ASSERT_EQ(p->error(), "1:8: missing : for identifier declaration");
} }
TEST_F(ParserImplTest, VariableIdentDecl_MissingType) { TEST_F(ParserImplTest, VariableIdentDecl_MissingType) {
ParserImpl p{"my_var :"}; auto p = parser("my_var :");
auto r = p.variable_ident_decl(); auto r = p->variable_ident_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:9: invalid type for identifier declaration"); ASSERT_EQ(p->error(), "1:9: invalid type for identifier declaration");
} }
TEST_F(ParserImplTest, VariableIdentDecl_InvalidIdent) { TEST_F(ParserImplTest, VariableIdentDecl_InvalidIdent) {
ParserImpl p{"123 : f32"}; auto p = parser("123 : f32");
std::string name; std::string name;
ast::type::Type* type; ast::type::Type* type;
std::tie(name, type) = p.variable_ident_decl(); std::tie(name, type) = p->variable_ident_decl();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
ASSERT_EQ(name, ""); ASSERT_EQ(name, "");
ASSERT_EQ(type, nullptr); ASSERT_EQ(type, nullptr);
auto t = p.next(); auto t = p->next();
ASSERT_TRUE(t.IsIntLiteral()); ASSERT_TRUE(t.IsIntLiteral());
} }
TEST_F(ParserImplTest, VariableIdentDecl_InvalidType) { TEST_F(ParserImplTest, VariableIdentDecl_InvalidType) {
ParserImpl p{"my_var : invalid"}; auto p = parser("my_var : invalid");
auto r = p.variable_ident_decl(); auto r = p->variable_ident_decl();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:10: unknown type alias 'invalid'"); ASSERT_EQ(p->error(), "1:10: unknown type alias 'invalid'");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -16,17 +16,16 @@
#include "src/ast/statement.h" #include "src/ast/statement.h"
#include "src/ast/variable_statement.h" #include "src/ast/variable_statement.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, VariableStmt_VariableDecl) { TEST_F(ParserImplTest, VariableStmt_VariableDecl) {
ParserImpl p{"var a : i32;"}; auto p = parser("var a : i32;");
auto e = p.variable_stmt(); auto e = p->variable_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsVariable()); ASSERT_TRUE(e->IsVariable());
ASSERT_NE(e->variable(), nullptr); ASSERT_NE(e->variable(), nullptr);
@ -36,9 +35,9 @@ TEST_F(ParserImplTest, VariableStmt_VariableDecl) {
} }
TEST_F(ParserImplTest, VariableStmt_VariableDecl_WithInit) { TEST_F(ParserImplTest, VariableStmt_VariableDecl_WithInit) {
ParserImpl p{"var a : i32 = 1;"}; auto p = parser("var a : i32 = 1;");
auto e = p.variable_stmt(); auto e = p->variable_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsVariable()); ASSERT_TRUE(e->IsVariable());
ASSERT_NE(e->variable(), nullptr); ASSERT_NE(e->variable(), nullptr);
@ -49,59 +48,59 @@ TEST_F(ParserImplTest, VariableStmt_VariableDecl_WithInit) {
} }
TEST_F(ParserImplTest, VariableStmt_VariableDecl_Invalid) { TEST_F(ParserImplTest, VariableStmt_VariableDecl_Invalid) {
ParserImpl p{"var a : invalid;"}; auto p = parser("var a : invalid;");
auto e = p.variable_stmt(); auto e = p->variable_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:9: unknown type alias 'invalid'"); EXPECT_EQ(p->error(), "1:9: unknown type alias 'invalid'");
} }
TEST_F(ParserImplTest, VariableStmt_VariableDecl_InitializerInvalid) { TEST_F(ParserImplTest, VariableStmt_VariableDecl_InitializerInvalid) {
ParserImpl p{"var a : i32 = if(a) {}"}; auto p = parser("var a : i32 = if(a) {}");
auto e = p.variable_stmt(); auto e = p->variable_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:15: missing initializer for variable declaration"); EXPECT_EQ(p->error(), "1:15: missing initializer for variable declaration");
} }
TEST_F(ParserImplTest, VariableStmt_Const) { TEST_F(ParserImplTest, VariableStmt_Const) {
ParserImpl p{"const a : i32 = 1"}; auto p = parser("const a : i32 = 1");
auto e = p.variable_stmt(); auto e = p->variable_stmt();
ASSERT_FALSE(p.has_error()) << p.error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsVariable()); ASSERT_TRUE(e->IsVariable());
} }
TEST_F(ParserImplTest, VariableStmt_Const_InvalidVarIdent) { TEST_F(ParserImplTest, VariableStmt_Const_InvalidVarIdent) {
ParserImpl p{"const a : invalid = 1"}; auto p = parser("const a : invalid = 1");
auto e = p.variable_stmt(); auto e = p->variable_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:11: unknown type alias 'invalid'"); EXPECT_EQ(p->error(), "1:11: unknown type alias 'invalid'");
} }
TEST_F(ParserImplTest, VariableStmt_Const_MissingEqual) { TEST_F(ParserImplTest, VariableStmt_Const_MissingEqual) {
ParserImpl p{"const a : i32 1"}; auto p = parser("const a : i32 1");
auto e = p.variable_stmt(); auto e = p->variable_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:15: missing = for constant declaration"); EXPECT_EQ(p->error(), "1:15: missing = for constant declaration");
} }
TEST_F(ParserImplTest, VariableStmt_Const_MissingInitializer) { TEST_F(ParserImplTest, VariableStmt_Const_MissingInitializer) {
ParserImpl p{"const a : i32 ="}; auto p = parser("const a : i32 =");
auto e = p.variable_stmt(); auto e = p->variable_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:16: missing initializer for const declaration"); EXPECT_EQ(p->error(), "1:16: missing initializer for const declaration");
} }
TEST_F(ParserImplTest, VariableStmt_Const_InvalidInitializer) { TEST_F(ParserImplTest, VariableStmt_Const_InvalidInitializer) {
ParserImpl p{"const a : i32 = if (a) {}"}; auto p = parser("const a : i32 = if (a) {}");
auto e = p.variable_stmt(); auto e = p->variable_stmt();
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:17: missing initializer for const declaration"); EXPECT_EQ(p->error(), "1:17: missing initializer for const declaration");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -15,12 +15,12 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/ast/storage_class.h" #include "src/ast/storage_class.h"
#include "src/reader/wgsl/parser_impl.h" #include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
namespace wgsl { namespace wgsl {
namespace {
using ParserImplTest = testing::Test;
struct VariableStorageData { struct VariableStorageData {
const char* input; const char* input;
@ -30,16 +30,41 @@ inline std::ostream& operator<<(std::ostream& out, VariableStorageData data) {
out << std::string(data.input); out << std::string(data.input);
return out; return out;
} }
using VariableStorageTest = testing::TestWithParam<VariableStorageData>;
class VariableStorageTest : public testing::TestWithParam<VariableStorageData> {
public:
VariableStorageTest() = default;
~VariableStorageTest() = default;
void SetUp() { ctx_.type_mgr = &tm_; }
void TearDown() {
impl_ = nullptr;
ctx_.type_mgr = nullptr;
}
ParserImpl* parser(const std::string& str) {
impl_ = std::make_unique<ParserImpl>(ctx_, str);
return impl_.get();
}
private:
std::unique_ptr<ParserImpl> impl_;
Context ctx_;
TypeManager tm_;
};
} // namespace
TEST_P(VariableStorageTest, Parses) { TEST_P(VariableStorageTest, Parses) {
auto params = GetParam(); auto params = GetParam();
ParserImpl p{std::string("<") + params.input + ">"}; auto p = parser(std::string("<") + params.input + ">");
auto sc = p.variable_storage_decoration(); auto sc = p->variable_storage_decoration();
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
EXPECT_EQ(sc, params.result); EXPECT_EQ(sc, params.result);
auto t = p.next(); auto t = p->next();
EXPECT_TRUE(t.IsEof()); EXPECT_TRUE(t.IsEof());
} }
INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P(
@ -60,37 +85,37 @@ INSTANTIATE_TEST_SUITE_P(
VariableStorageData{"function", ast::StorageClass::kFunction})); VariableStorageData{"function", ast::StorageClass::kFunction}));
TEST_F(ParserImplTest, VariableStorageDecoration_NoMatch) { TEST_F(ParserImplTest, VariableStorageDecoration_NoMatch) {
ParserImpl p{"<not-a-storage-class>"}; auto p = parser("<not-a-storage-class>");
auto sc = p.variable_storage_decoration(); auto sc = p->variable_storage_decoration();
ASSERT_EQ(sc, ast::StorageClass::kNone); ASSERT_EQ(sc, ast::StorageClass::kNone);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:2: invalid storage class for variable decoration"); ASSERT_EQ(p->error(), "1:2: invalid storage class for variable decoration");
} }
TEST_F(ParserImplTest, VariableStorageDecoration_Empty) { TEST_F(ParserImplTest, VariableStorageDecoration_Empty) {
ParserImpl p{"<>"}; auto p = parser("<>");
auto sc = p.variable_storage_decoration(); auto sc = p->variable_storage_decoration();
ASSERT_EQ(sc, ast::StorageClass::kNone); ASSERT_EQ(sc, ast::StorageClass::kNone);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:2: invalid storage class for variable decoration"); ASSERT_EQ(p->error(), "1:2: invalid storage class for variable decoration");
} }
TEST_F(ParserImplTest, VariableStorageDecoration_MissingLessThan) { TEST_F(ParserImplTest, VariableStorageDecoration_MissingLessThan) {
ParserImpl p{"in>"}; auto p = parser("in>");
auto sc = p.variable_storage_decoration(); auto sc = p->variable_storage_decoration();
ASSERT_EQ(sc, ast::StorageClass::kNone); ASSERT_EQ(sc, ast::StorageClass::kNone);
ASSERT_FALSE(p.has_error()); ASSERT_FALSE(p->has_error());
auto t = p.next(); auto t = p->next();
ASSERT_TRUE(t.IsIn()); ASSERT_TRUE(t.IsIn());
} }
TEST_F(ParserImplTest, VariableStorageDecoration_MissingGreaterThan) { TEST_F(ParserImplTest, VariableStorageDecoration_MissingGreaterThan) {
ParserImpl p{"<in"}; auto p = parser("<in");
auto sc = p.variable_storage_decoration(); auto sc = p->variable_storage_decoration();
ASSERT_EQ(sc, ast::StorageClass::kNone); ASSERT_EQ(sc, ast::StorageClass::kNone);
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p.error(), "1:4: missing > for variable decoration"); ASSERT_EQ(p->error(), "1:4: missing > for variable decoration");
} }
} // namespace wgsl } // namespace wgsl

View File

@ -15,6 +15,7 @@
#include "src/reader/wgsl/parser.h" #include "src/reader/wgsl/parser.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/context.h"
namespace tint { namespace tint {
namespace reader { namespace reader {
@ -23,12 +24,19 @@ namespace wgsl {
using ParserTest = testing::Test; using ParserTest = testing::Test;
TEST_F(ParserTest, Empty) { TEST_F(ParserTest, Empty) {
Parser p{""}; TypeManager tm;
Context ctx;
ctx.type_mgr = &tm;
Parser p(ctx, "");
ASSERT_TRUE(p.Parse()) << p.error(); ASSERT_TRUE(p.Parse()) << p.error();
} }
TEST_F(ParserTest, DISABLED_Parses) { TEST_F(ParserTest, DISABLED_Parses) {
Parser p{R"( TypeManager tm;
Context ctx;
ctx.type_mgr = &tm;
Parser p(ctx, R"(
import "GLSL.std.430" as glsl; import "GLSL.std.430" as glsl;
[[location 0]] var<out> gl_FragColor : vec4<f32>; [[location 0]] var<out> gl_FragColor : vec4<f32>;
@ -36,7 +44,7 @@ import "GLSL.std.430" as glsl;
fn main() -> void { fn main() -> void {
gl_FragColor = vec4<f32>(.4, .2, .3, 1); gl_FragColor = vec4<f32>(.4, .2, .3, 1);
} }
)"}; )");
ASSERT_TRUE(p.Parse()) << p.error(); ASSERT_TRUE(p.Parse()) << p.error();
auto m = p.module(); auto m = p.module();
@ -46,12 +54,13 @@ fn main() -> void {
} }
TEST_F(ParserTest, DISABLED_HandlesError) { TEST_F(ParserTest, DISABLED_HandlesError) {
Parser p{R"( Context ctx;
Parser p(ctx, R"(
import "GLSL.std.430" as glsl; import "GLSL.std.430" as glsl;
fn main() -> { # missing return type fn main() -> { # missing return type
return; return;
})"}; })");
ASSERT_FALSE(p.Parse()); ASSERT_FALSE(p.Parse());
ASSERT_TRUE(p.has_error()); ASSERT_TRUE(p.has_error());

View File

@ -17,25 +17,6 @@
#include <utility> #include <utility>
namespace tint { namespace tint {
namespace {
TypeManager* manager_ = nullptr;
} // namespace
// static
TypeManager* TypeManager::Instance() {
if (!manager_) {
manager_ = new TypeManager();
}
return manager_;
}
// static
void TypeManager::Destroy() {
delete manager_;
manager_ = nullptr;
}
TypeManager::TypeManager() = default; TypeManager::TypeManager() = default;

View File

@ -24,16 +24,10 @@
namespace tint { namespace tint {
/// The type manager holds all the pointers to the known types. /// The type manager holds all the pointers to the known types.
///
/// Note, the type manager is a singleton. Any synchronization for the manager
/// must be done by the caller.
class TypeManager { class TypeManager {
public: public:
/// @returns a pointer to the type manager TypeManager();
static TypeManager* Instance(); ~TypeManager();
/// Frees the type manager and any associated types. The types should not be
/// used after the manager is freed.
static void Destroy();
/// Get the given type from the type manager /// Get the given type from the type manager
/// @param type The type to register /// @param type The type to register
@ -41,9 +35,6 @@ class TypeManager {
ast::type::Type* Get(std::unique_ptr<ast::type::Type> type); ast::type::Type* Get(std::unique_ptr<ast::type::Type> type);
private: private:
TypeManager();
~TypeManager();
std::unordered_map<std::string, std::unique_ptr<ast::type::Type>> types_; std::unordered_map<std::string, std::unique_ptr<ast::type::Type>> types_;
}; };

View File

@ -22,60 +22,33 @@ namespace tint {
using TypeManagerTest = testing::Test; using TypeManagerTest = testing::Test;
TEST_F(TypeManagerTest, Singleton) {
auto tm = TypeManager::Instance();
ASSERT_NE(tm, nullptr);
ASSERT_EQ(tm, TypeManager::Instance());
TypeManager::Destroy();
}
TEST_F(TypeManagerTest, Destroy) {
auto tm = TypeManager::Instance();
ASSERT_NE(tm, nullptr);
ASSERT_EQ(tm, TypeManager::Instance());
TypeManager::Destroy();
tm = TypeManager::Instance();
ASSERT_NE(tm, nullptr);
TypeManager::Destroy();
}
TEST_F(TypeManagerTest, GetUnregistered) { TEST_F(TypeManagerTest, GetUnregistered) {
auto tm = TypeManager::Instance(); TypeManager tm;
auto t = tm->Get(std::make_unique<ast::type::I32Type>()); auto t = tm.Get(std::make_unique<ast::type::I32Type>());
ASSERT_NE(t, nullptr); ASSERT_NE(t, nullptr);
EXPECT_TRUE(t->IsI32()); EXPECT_TRUE(t->IsI32());
TypeManager::Destroy();
} }
TEST_F(TypeManagerTest, GetSameTypeReturnsSamePtr) { TEST_F(TypeManagerTest, GetSameTypeReturnsSamePtr) {
auto tm = TypeManager::Instance(); TypeManager tm;
auto t = tm->Get(std::make_unique<ast::type::I32Type>()); auto t = tm.Get(std::make_unique<ast::type::I32Type>());
ASSERT_NE(t, nullptr); ASSERT_NE(t, nullptr);
EXPECT_TRUE(t->IsI32()); EXPECT_TRUE(t->IsI32());
auto t2 = tm->Get(std::make_unique<ast::type::I32Type>()); auto t2 = tm.Get(std::make_unique<ast::type::I32Type>());
EXPECT_EQ(t, t2); EXPECT_EQ(t, t2);
TypeManager::Destroy();
} }
TEST_F(TypeManagerTest, GetDifferentTypeReturnsDifferentPtr) { TEST_F(TypeManagerTest, GetDifferentTypeReturnsDifferentPtr) {
auto tm = TypeManager::Instance(); TypeManager tm;
auto t = tm->Get(std::make_unique<ast::type::I32Type>()); auto t = tm.Get(std::make_unique<ast::type::I32Type>());
ASSERT_NE(t, nullptr); ASSERT_NE(t, nullptr);
EXPECT_TRUE(t->IsI32()); EXPECT_TRUE(t->IsI32());
auto t2 = tm->Get(std::make_unique<ast::type::U32Type>()); auto t2 = tm.Get(std::make_unique<ast::type::U32Type>());
ASSERT_NE(t2, nullptr); ASSERT_NE(t2, nullptr);
EXPECT_NE(t, t2); EXPECT_NE(t, t2);
EXPECT_TRUE(t2->IsU32()); EXPECT_TRUE(t2->IsU32());
TypeManager::Destroy();
} }
} // namespace tint } // namespace tint