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 <vector>
#include "src/context.h"
#include "src/reader/reader.h"
#include "src/type_determiner.h"
#include "src/type_manager.h"
#include "src/validator.h"
#include "src/writer/writer.h"
@ -250,6 +252,11 @@ int main(int argc, const char** argv) {
return 1;
}
tint::TypeManager type_manager;
tint::Context ctx;
ctx.type_mgr = &type_manager;
std::unique_ptr<tint::reader::Reader> reader;
#if TINT_BUILD_WGSL_READER
if (options.input_filename.size() > 5 &&
@ -260,7 +267,7 @@ int main(int argc, const char** argv) {
return 1;
}
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
@ -272,7 +279,7 @@ int main(int argc, const char** argv) {
if (!ReadFile<uint32_t>(options.input_filename, &data)) {
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

View File

@ -387,6 +387,7 @@ if(${TINT_BUILD_WGSL_READER})
reader/wgsl/parser_impl_switch_body_test.cc
reader/wgsl/parser_impl_switch_stmt_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_decl_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 reader {
Reader::Reader() = default;
Reader::Reader(const Context& ctx) : ctx_(ctx) {}
Reader::~Reader() = default;

View File

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

View File

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

View File

@ -31,8 +31,9 @@ class ParserImpl;
class Parser : public Reader {
public:
/// Creates a new parser
/// @param ctx the context object
/// @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
~Parser() override;

View File

@ -44,8 +44,9 @@ const spv_target_env kTargetEnv = SPV_ENV_WEBGPU_0;
} // namespace
ParserImpl::ParserImpl(const std::vector<uint32_t>& spv_binary)
: Reader(),
ParserImpl::ParserImpl(const Context& ctx,
const std::vector<uint32_t>& spv_binary)
: Reader(ctx),
spv_binary_(spv_binary),
fail_stream_(&success_, &errors_),
namer_(fail_stream_),
@ -75,6 +76,11 @@ ParserImpl::ParserImpl(const std::vector<uint32_t>& spv_binary)
ParserImpl::~ParserImpl() = default;
bool ParserImpl::Parse() {
if (ctx_.type_mgr == nullptr) {
Fail() << "Missing type manager";
return false;
}
if (!success_) {
return false;
}
@ -125,22 +131,21 @@ ast::type::Type* ParserImpl::ConvertType(uint32_t type_id) {
}
ast::type::Type* result = nullptr;
TypeManager* tint_tm = TypeManager::Instance();
switch (spirv_type->kind()) {
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;
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;
case spvtools::opt::analysis::Type::kInteger: {
const auto* int_ty = spirv_type->AsInteger();
if (int_ty->width() == 32) {
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 {
result = tint_tm->Get(std::make_unique<ast::type::U32Type>());
result = ctx_.type_mgr->Get(std::make_unique<ast::type::U32Type>());
}
} else {
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: {
const auto* float_ty = spirv_type->AsFloat();
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 {
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();
auto* ast_elem_ty = ConvertType(type_mgr_->GetId(vec_ty->element_type()));
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));
}
// 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();
auto* ast_scalar_ty = ConvertType(type_mgr_->GetId(scalar_ty));
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));
}
// In the error case, we'll already have emitted a diagnostic.

View File

@ -45,8 +45,9 @@ namespace spirv {
class ParserImpl : Reader {
public:
/// Creates a new parser
/// @param ctx the context object
/// @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
~ParserImpl() override;

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -18,17 +18,16 @@
#include "src/ast/identifier_expression.h"
#include "src/ast/relational_expression.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint {
namespace reader {
namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, AndExpression_Parses) {
ParserImpl p{"a & true"};
auto e = p.and_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("a & true");
auto e = p->and_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRelational());
@ -48,24 +47,24 @@ TEST_F(ParserImplTest, AndExpression_Parses) {
}
TEST_F(ParserImplTest, AndExpression_InvalidLHS) {
ParserImpl p{"if (a) {} & true"};
auto e = p.and_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("if (a) {} & true");
auto e = p->and_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e, nullptr);
}
TEST_F(ParserImplTest, AndExpression_InvalidRHS) {
ParserImpl p{"true & if (a) {}"};
auto e = p.and_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("true & if (a) {}");
auto e = p->and_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"a true"};
auto e = p.and_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("a true");
auto e = p->and_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsIdentifier());
}

View File

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

View File

@ -21,17 +21,16 @@
#include "src/ast/literal.h"
#include "src/ast/member_accessor_expression.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint {
namespace reader {
namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, AssignmentStmt_Parses_ToVariable) {
ParserImpl p{"a = 123"};
auto e = p.assignment_stmt();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("a = 123");
auto e = p->assignment_stmt();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsAssign());
@ -53,9 +52,9 @@ TEST_F(ParserImplTest, AssignmentStmt_Parses_ToVariable) {
}
TEST_F(ParserImplTest, AssignmentStmt_Parses_ToMember) {
ParserImpl p{"a.b.c[2].d = 123"};
auto e = p.assignment_stmt();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("a.b.c[2].d = 123");
auto e = p->assignment_stmt();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsAssign());
@ -109,26 +108,26 @@ TEST_F(ParserImplTest, AssignmentStmt_Parses_ToMember) {
}
TEST_F(ParserImplTest, AssignmentStmt_MissingEqual) {
ParserImpl p{"a.b.c[2].d 123"};
auto e = p.assignment_stmt();
ASSERT_TRUE(p.has_error());
auto p = parser("a.b.c[2].d 123");
auto e = p->assignment_stmt();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"if (true) {} = 123"};
auto e = p.assignment_stmt();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("if (true) {} = 123");
auto e = p->assignment_stmt();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e, nullptr);
}
TEST_F(ParserImplTest, AssignmentStmt_InvalidRHS) {
ParserImpl p{"a.b.c[2].d = if (true) {}"};
auto e = p.assignment_stmt();
ASSERT_TRUE(p.has_error());
auto p = parser("a.b.c[2].d = if (true) {}");
auto e = p->assignment_stmt();
ASSERT_TRUE(p->has_error());
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

View File

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

View File

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

View File

@ -15,12 +15,12 @@
#include "gtest/gtest.h"
#include "src/ast/builtin.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint {
namespace reader {
namespace wgsl {
using ParserImplTest = testing::Test;
namespace {
struct BuiltinData {
const char* input;
@ -30,16 +30,41 @@ inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
out << std::string(data.input);
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) {
auto params = GetParam();
ParserImpl p{params.input};
auto p = parser(params.input);
auto builtin = p.builtin_decoration();
ASSERT_FALSE(p.has_error());
auto builtin = p->builtin_decoration();
ASSERT_FALSE(p->has_error());
EXPECT_EQ(builtin, params.result);
auto t = p.next();
auto t = p->next();
EXPECT_TRUE(t.IsEof());
}
INSTANTIATE_TEST_SUITE_P(
@ -60,11 +85,11 @@ INSTANTIATE_TEST_SUITE_P(
ast::Builtin::kGlobalInvocationId}));
TEST_F(ParserImplTest, BuiltinDecoration_NoMatch) {
ParserImpl p{"not-a-builtin"};
auto builtin = p.builtin_decoration();
auto p = parser("not-a-builtin");
auto builtin = p->builtin_decoration();
ASSERT_EQ(builtin, ast::Builtin::kNone);
auto t = p.next();
auto t = p->next();
EXPECT_TRUE(t.IsIdentifier());
EXPECT_EQ(t.to_str(), "not");
}

View File

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

View File

@ -19,17 +19,16 @@
#include "src/ast/type/vector_type.h"
#include "src/ast/type_initializer_expression.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint {
namespace reader {
namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, ConstExpr_TypeDecl) {
ParserImpl p{"vec2<f32>(1., 2.)"};
auto e = p.const_expr();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("vec2<f32>(1., 2.)");
auto e = p->const_expr();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsInitializer());
ASSERT_TRUE(e->AsInitializer()->IsTypeInitializer());
@ -55,57 +54,57 @@ TEST_F(ParserImplTest, ConstExpr_TypeDecl) {
}
TEST_F(ParserImplTest, ConstExpr_TypeDecl_MissingRightParen) {
ParserImpl p{"vec2<f32>(1., 2."};
auto e = p.const_expr();
ASSERT_TRUE(p.has_error());
auto p = parser("vec2<f32>(1., 2.");
auto e = p->const_expr();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"vec2<f32> 1., 2.)"};
auto e = p.const_expr();
ASSERT_TRUE(p.has_error());
auto p = parser("vec2<f32> 1., 2.)");
auto e = p->const_expr();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"vec2<f32>(1.,)"};
auto e = p.const_expr();
ASSERT_TRUE(p.has_error());
auto p = parser("vec2<f32>(1.,)");
auto e = p->const_expr();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"vec2<f32>(1. 2."};
auto e = p.const_expr();
ASSERT_TRUE(p.has_error());
auto p = parser("vec2<f32>(1. 2.");
auto e = p->const_expr();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"vec2<f32>()"};
auto e = p.const_expr();
ASSERT_TRUE(p.has_error());
auto p = parser("vec2<f32>()");
auto e = p->const_expr();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"vec2<f32>(1., if(a) {})"};
auto e = p.const_expr();
ASSERT_TRUE(p.has_error());
auto p = parser("vec2<f32>(1., if(a) {})");
auto e = p->const_expr();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"true"};
auto e = p.const_expr();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("true");
auto e = p->const_expr();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsInitializer());
ASSERT_TRUE(e->AsInitializer()->IsConstInitializer());
@ -115,11 +114,11 @@ TEST_F(ParserImplTest, ConstExpr_ConstLiteral) {
}
TEST_F(ParserImplTest, ConstExpr_ConstLiteral_Invalid) {
ParserImpl p{"invalid"};
auto e = p.const_expr();
ASSERT_TRUE(p.has_error());
auto p = parser("invalid");
auto e = p->const_expr();
ASSERT_TRUE(p->has_error());
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

View File

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

View File

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

View File

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

View File

@ -15,12 +15,12 @@
#include "gtest/gtest.h"
#include "src/ast/derivative_modifier.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint {
namespace reader {
namespace wgsl {
using ParserImplTest = testing::Test;
namespace {
struct DerivativeModifierData {
const char* input;
@ -31,16 +31,42 @@ inline std::ostream& operator<<(std::ostream& out,
out << std::string(data.input);
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) {
auto params = GetParam();
ParserImpl p{params.input};
auto p = parser(params.input);
auto mod = p.derivative_modifier();
ASSERT_FALSE(p.has_error());
auto mod = p->derivative_modifier();
ASSERT_FALSE(p->has_error());
EXPECT_EQ(mod, params.result);
auto t = p.next();
auto t = p->next();
EXPECT_TRUE(t.IsEof());
}
INSTANTIATE_TEST_SUITE_P(
@ -51,11 +77,11 @@ INSTANTIATE_TEST_SUITE_P(
DerivativeModifierData{"coarse", ast::DerivativeModifier::kCoarse}));
TEST_F(ParserImplTest, DerivativeModifier_NoMatch) {
ParserImpl p{"not-a-modifier"};
auto stage = p.derivative_modifier();
auto p = parser("not-a-modifier");
auto stage = p->derivative_modifier();
ASSERT_EQ(stage, ast::DerivativeModifier::kNone);
auto t = p.next();
auto t = p->next();
EXPECT_TRUE(t.IsIdentifier());
EXPECT_EQ(t.to_str(), "not");
}

View File

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

View File

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

View File

@ -15,105 +15,104 @@
#include "gtest/gtest.h"
#include "src/ast/variable.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint {
namespace reader {
namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, EntryPoint_Parses) {
ParserImpl p{"entry_point fragment = main"};
auto e = p.entry_point_decl();
auto p = parser("entry_point fragment = main");
auto e = p->entry_point_decl();
ASSERT_NE(e, nullptr);
ASSERT_FALSE(p.has_error());
ASSERT_FALSE(p->has_error());
EXPECT_EQ(e->stage(), ast::PipelineStage::kFragment);
EXPECT_EQ(e->name(), "main");
EXPECT_EQ(e->function_name(), "main");
}
TEST_F(ParserImplTest, EntryPoint_ParsesWithStringName) {
ParserImpl p{R"(entry_point vertex as "main" = vtx_main)"};
auto e = p.entry_point_decl();
auto p = parser(R"(entry_point vertex as "main" = vtx_main)");
auto e = p->entry_point_decl();
ASSERT_NE(e, nullptr);
ASSERT_FALSE(p.has_error());
ASSERT_FALSE(p->has_error());
EXPECT_EQ(e->stage(), ast::PipelineStage::kVertex);
EXPECT_EQ(e->name(), "main");
EXPECT_EQ(e->function_name(), "vtx_main");
}
TEST_F(ParserImplTest, EntryPoint_ParsesWithIdentName) {
ParserImpl p{R"(entry_point vertex as main = vtx_main)"};
auto e = p.entry_point_decl();
auto p = parser(R"(entry_point vertex as main = vtx_main)");
auto e = p->entry_point_decl();
ASSERT_NE(e, nullptr);
ASSERT_FALSE(p.has_error());
ASSERT_FALSE(p->has_error());
EXPECT_EQ(e->stage(), ast::PipelineStage::kVertex);
EXPECT_EQ(e->name(), "main");
EXPECT_EQ(e->function_name(), "vtx_main");
}
TEST_F(ParserImplTest, EntryPoint_MissingFnName) {
ParserImpl p{R"(entry_point vertex as main =)"};
auto e = p.entry_point_decl();
ASSERT_TRUE(p.has_error());
auto p = parser(R"(entry_point vertex as main =)");
auto e = p->entry_point_decl();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{R"(entry_point vertex as main = 123)"};
auto e = p.entry_point_decl();
ASSERT_TRUE(p.has_error());
auto p = parser(R"(entry_point vertex as main = 123)");
auto e = p->entry_point_decl();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{R"(entry_point vertex as main vtx_main)"};
auto e = p.entry_point_decl();
ASSERT_TRUE(p.has_error());
auto p = parser(R"(entry_point vertex as main vtx_main)");
auto e = p->entry_point_decl();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{R"(entry_point vertex as = vtx_main)"};
auto e = p.entry_point_decl();
ASSERT_TRUE(p.has_error());
auto p = parser(R"(entry_point vertex as = vtx_main)");
auto e = p->entry_point_decl();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{R"(entry_point vertex as 123 = vtx_main)"};
auto e = p.entry_point_decl();
ASSERT_TRUE(p.has_error());
auto p = parser(R"(entry_point vertex as 123 = vtx_main)");
auto e = p->entry_point_decl();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{R"(entry_point as 123 = vtx_main)"};
auto e = p.entry_point_decl();
ASSERT_TRUE(p.has_error());
auto p = parser(R"(entry_point as 123 = vtx_main)");
auto e = p->entry_point_decl();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{R"(entry_point = vtx_main)"};
auto e = p.entry_point_decl();
ASSERT_TRUE(p.has_error());
auto p = parser(R"(entry_point = vtx_main)");
auto e = p->entry_point_decl();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{R"(entry_point invalid = vtx_main)"};
auto e = p.entry_point_decl();
ASSERT_TRUE(p.has_error());
auto p = parser(R"(entry_point invalid = vtx_main)");
auto e = p->entry_point_decl();
ASSERT_TRUE(p->has_error());
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

View File

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

View File

@ -18,17 +18,16 @@
#include "src/ast/identifier_expression.h"
#include "src/ast/relational_expression.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint {
namespace reader {
namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, ExclusiveOrExpression_Parses) {
ParserImpl p{"a ^ true"};
auto e = p.exclusive_or_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("a ^ true");
auto e = p->exclusive_or_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRelational());
@ -48,24 +47,24 @@ TEST_F(ParserImplTest, ExclusiveOrExpression_Parses) {
}
TEST_F(ParserImplTest, ExclusiveOrExpression_InvalidLHS) {
ParserImpl p{"if (a) {} ^ true"};
auto e = p.exclusive_or_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("if (a) {} ^ true");
auto e = p->exclusive_or_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e, nullptr);
}
TEST_F(ParserImplTest, ExclusiveOrExpression_InvalidRHS) {
ParserImpl p{"true ^ if (a) {}"};
auto e = p.exclusive_or_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("true ^ if (a) {}");
auto e = p->exclusive_or_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"a true"};
auto e = p.exclusive_or_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("a true");
auto e = p->exclusive_or_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsIdentifier());
}

View File

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

View File

@ -16,17 +16,16 @@
#include "src/ast/function.h"
#include "src/ast/type/type.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint {
namespace reader {
namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, FunctionHeader) {
ParserImpl p{"fn main(a : i32, b: f32) -> void"};
auto f = p.function_header();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("fn main(a : i32, b: f32) -> void");
auto f = p->function_header();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(f, nullptr);
EXPECT_EQ(f->name(), "main");
@ -37,67 +36,67 @@ TEST_F(ParserImplTest, FunctionHeader) {
}
TEST_F(ParserImplTest, FunctionHeader_MissingIdent) {
ParserImpl p{"fn () ->"};
auto f = p.function_header();
ASSERT_TRUE(p.has_error());
auto p = parser("fn () ->");
auto f = p->function_header();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"fn 133main() -> i32"};
auto f = p.function_header();
ASSERT_TRUE(p.has_error());
auto p = parser("fn 133main() -> i32");
auto f = p->function_header();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"fn main) -> i32"};
auto f = p.function_header();
ASSERT_TRUE(p.has_error());
auto p = parser("fn main) -> i32");
auto f = p->function_header();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"fn main(a :i32,) -> i32"};
auto f = p.function_header();
ASSERT_TRUE(p.has_error());
auto p = parser("fn main(a :i32,) -> i32");
auto f = p->function_header();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"fn main( -> i32"};
auto f = p.function_header();
ASSERT_TRUE(p.has_error());
auto p = parser("fn main( -> i32");
auto f = p->function_header();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"fn main() i32"};
auto f = p.function_header();
ASSERT_TRUE(p.has_error());
auto p = parser("fn main() i32");
auto f = p->function_header();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"fn main() -> invalid"};
auto f = p.function_header();
ASSERT_TRUE(p.has_error());
auto p = parser("fn main() -> invalid");
auto f = p->function_header();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"fn main() ->"};
auto f = p.function_header();
ASSERT_TRUE(p.has_error());
auto p = parser("fn main() ->");
auto f = p->function_header();
ASSERT_TRUE(p->has_error());
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

View File

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

View File

@ -16,17 +16,16 @@
#include "src/ast/decorated_variable.h"
#include "src/ast/variable_decoration.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint {
namespace reader {
namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, GlobalConstantDecl) {
ParserImpl p{"const a : f32 = 1."};
auto e = p.global_constant_decl();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("const a : f32 = 1.");
auto e = p->global_constant_decl();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
EXPECT_TRUE(e->is_const());
@ -39,35 +38,35 @@ TEST_F(ParserImplTest, GlobalConstantDecl) {
}
TEST_F(ParserImplTest, GlobalConstantDecl_MissingEqual) {
ParserImpl p{"const a: f32 1."};
auto e = p.global_constant_decl();
ASSERT_TRUE(p.has_error());
auto p = parser("const a: f32 1.");
auto e = p->global_constant_decl();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"const a: invalid = 1."};
auto e = p.global_constant_decl();
ASSERT_TRUE(p.has_error());
auto p = parser("const a: invalid = 1.");
auto e = p->global_constant_decl();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"const a: f32 = if (a) {}"};
auto e = p.global_constant_decl();
ASSERT_TRUE(p.has_error());
auto p = parser("const a: f32 = if (a) {}");
auto e = p->global_constant_decl();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"const a: f32 ="};
auto e = p.global_constant_decl();
ASSERT_TRUE(p.has_error());
auto p = parser("const a: f32 =");
auto e = p->global_constant_decl();
ASSERT_TRUE(p->has_error());
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

View File

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

View File

@ -16,17 +16,16 @@
#include "src/ast/decorated_variable.h"
#include "src/ast/variable_decoration.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint {
namespace reader {
namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, GlobalVariableDecl_WithoutInitializer) {
ParserImpl p{"var<out> a : f32"};
auto e = p.global_variable_decl();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("var<out> a : f32");
auto e = p->global_variable_decl();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
EXPECT_EQ(e->name(), "a");
@ -38,9 +37,9 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithoutInitializer) {
}
TEST_F(ParserImplTest, GlobalVariableDecl_WithInitializer) {
ParserImpl p{"var<out> a : f32 = 1."};
auto e = p.global_variable_decl();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("var<out> a : f32 = 1.");
auto e = p->global_variable_decl();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
EXPECT_EQ(e->name(), "a");
@ -55,9 +54,9 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithInitializer) {
}
TEST_F(ParserImplTest, GlobalVariableDecl_WithDecoration) {
ParserImpl p{"[[binding 2, set 1]] var<out> a : f32"};
auto e = p.global_variable_decl();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("[[binding 2, set 1]] var<out> a : f32");
auto e = p->global_variable_decl();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsDecorated());
@ -78,27 +77,27 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithDecoration) {
}
TEST_F(ParserImplTest, GlobalVariableDecl_InvalidDecoration) {
ParserImpl p{"[[binding]] var<out> a : f32"};
auto e = p.global_variable_decl();
ASSERT_TRUE(p.has_error());
auto p = parser("[[binding]] var<out> a : f32");
auto e = p->global_variable_decl();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"var<out> a : f32 = if (a) {}"};
auto e = p.global_variable_decl();
ASSERT_TRUE(p.has_error());
auto p = parser("var<out> a : f32 = if (a) {}");
auto e = p->global_variable_decl();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"var<invalid> a : f32;"};
auto e = p.global_variable_decl();
ASSERT_TRUE(p.has_error());
auto p = parser("var<invalid> a : f32;");
auto e = p->global_variable_decl();
ASSERT_TRUE(p->has_error());
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

View File

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

View File

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

View File

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

View File

@ -18,17 +18,16 @@
#include "src/ast/identifier_expression.h"
#include "src/ast/relational_expression.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint {
namespace reader {
namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, LogicalAndExpression_Parses) {
ParserImpl p{"a && true"};
auto e = p.logical_and_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("a && true");
auto e = p->logical_and_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRelational());
@ -48,24 +47,24 @@ TEST_F(ParserImplTest, LogicalAndExpression_Parses) {
}
TEST_F(ParserImplTest, LogicalAndExpression_InvalidLHS) {
ParserImpl p{"if (a) {} && true"};
auto e = p.logical_and_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("if (a) {} && true");
auto e = p->logical_and_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e, nullptr);
}
TEST_F(ParserImplTest, LogicalAndExpression_InvalidRHS) {
ParserImpl p{"true && if (a) {}"};
auto e = p.logical_and_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("true && if (a) {}");
auto e = p->logical_and_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"a true"};
auto e = p.logical_and_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("a true");
auto e = p->logical_and_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsIdentifier());
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -15,12 +15,12 @@
#include "gtest/gtest.h"
#include "src/ast/pipeline_stage.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint {
namespace reader {
namespace wgsl {
using ParserImplTest = testing::Test;
namespace {
struct PipelineStageData {
const char* input;
@ -30,16 +30,41 @@ inline std::ostream& operator<<(std::ostream& out, PipelineStageData data) {
out << std::string(data.input);
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) {
auto params = GetParam();
ParserImpl p{params.input};
auto p = parser(params.input);
auto stage = p.pipeline_stage();
ASSERT_FALSE(p.has_error());
auto stage = p->pipeline_stage();
ASSERT_FALSE(p->has_error());
EXPECT_EQ(stage, params.result);
auto t = p.next();
auto t = p->next();
EXPECT_TRUE(t.IsEof());
}
INSTANTIATE_TEST_SUITE_P(
@ -51,11 +76,11 @@ INSTANTIATE_TEST_SUITE_P(
PipelineStageData{"compute", ast::PipelineStage::kCompute}));
TEST_F(ParserImplTest, PipelineStage_NoMatch) {
ParserImpl p{"not-a-stage"};
auto stage = p.pipeline_stage();
auto p = parser("not-a-stage");
auto stage = p->pipeline_stage();
ASSERT_EQ(stage, ast::PipelineStage::kNone);
auto t = p.next();
auto t = p->next();
EXPECT_TRUE(t.IsIdentifier());
EXPECT_EQ(t.to_str(), "not");
}

View File

@ -23,17 +23,16 @@
#include "src/ast/unary_method_expression.h"
#include "src/ast/unary_op_expression.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint {
namespace reader {
namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, PostfixExpression_Array_ConstantIndex) {
ParserImpl p{"a[1]"};
auto e = p.postfix_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("a[1]");
auto e = p->postfix_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsArrayAccessor());
@ -52,9 +51,9 @@ TEST_F(ParserImplTest, PostfixExpression_Array_ConstantIndex) {
}
TEST_F(ParserImplTest, PostfixExpression_Array_ExpressionIndex) {
ParserImpl p{"a[1 + b / 4]"};
auto e = p.postfix_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("a[1 + b / 4]");
auto e = p->postfix_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsArrayAccessor());
@ -69,33 +68,33 @@ TEST_F(ParserImplTest, PostfixExpression_Array_ExpressionIndex) {
}
TEST_F(ParserImplTest, PostfixExpression_Array_MissingIndex) {
ParserImpl p{"a[]"};
auto e = p.postfix_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("a[]");
auto e = p->postfix_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"a[1"};
auto e = p.postfix_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("a[1");
auto e = p->postfix_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"a[if(a() {})]"};
auto e = p.postfix_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("a[if(a() {})]");
auto e = p->postfix_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"a()"};
auto e = p.postfix_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("a()");
auto e = p->postfix_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsCall());
@ -110,9 +109,9 @@ TEST_F(ParserImplTest, PostfixExpression_Call_Empty) {
}
TEST_F(ParserImplTest, PostfixExpression_Call_WithArgs) {
ParserImpl p{"std::test(1, b, 2 + 3 / b)"};
auto e = p.postfix_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("std::test(1, b, 2 + 3 / b)");
auto e = p->postfix_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsCall());
@ -131,33 +130,33 @@ TEST_F(ParserImplTest, PostfixExpression_Call_WithArgs) {
}
TEST_F(ParserImplTest, PostfixExpression_Call_InvalidArg) {
ParserImpl p{"a(if(a) {})"};
auto e = p.postfix_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("a(if(a) {})");
auto e = p->postfix_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"a(b, )"};
auto e = p.postfix_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("a(b, )");
auto e = p->postfix_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"a("};
auto e = p.postfix_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("a(");
auto e = p->postfix_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"a.b"};
auto e = p.postfix_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("a.b");
auto e = p->postfix_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsMemberAccessor());
@ -172,25 +171,25 @@ TEST_F(ParserImplTest, PostfixExpression_MemberAccessor) {
}
TEST_F(ParserImplTest, PostfixExpression_MemberAccesssor_InvalidIdent) {
ParserImpl p{"a.if"};
auto e = p.postfix_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("a.if");
auto e = p->postfix_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"a."};
auto e = p.postfix_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("a.");
auto e = p->postfix_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"a b"};
auto e = p.postfix_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("a b");
auto e = p->postfix_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsIdentifier());
}

View File

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

View File

@ -27,18 +27,17 @@
#include "src/ast/unary_method_expression.h"
#include "src/ast/unary_op_expression.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
#include "src/type_manager.h"
namespace tint {
namespace reader {
namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, PrimaryExpression_Ident) {
ParserImpl p{"a"};
auto e = p.primary_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("a");
auto e = p->primary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsIdentifier());
auto ident = e->AsIdentifier();
@ -47,9 +46,9 @@ TEST_F(ParserImplTest, PrimaryExpression_Ident) {
}
TEST_F(ParserImplTest, PrimaryExpression_Ident_WithNamespace) {
ParserImpl p{"a::b::c::d"};
auto e = p.primary_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("a::b::c::d");
auto e = p->primary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsIdentifier());
auto ident = e->AsIdentifier();
@ -61,17 +60,17 @@ TEST_F(ParserImplTest, PrimaryExpression_Ident_WithNamespace) {
}
TEST_F(ParserImplTest, PrimaryExpression_Ident_MissingIdent) {
ParserImpl p{"a::"};
auto e = p.primary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("a::");
auto e = p->primary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"vec4<i32>(1, 2, 3, 4))"};
auto e = p.primary_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("vec4<i32>(1, 2, 3, 4))");
auto e = p->primary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsInitializer());
ASSERT_TRUE(e->AsInitializer()->IsTypeInitializer());
@ -105,41 +104,41 @@ TEST_F(ParserImplTest, PrimaryExpression_TypeDecl) {
}
TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_InvalidTypeDecl) {
ParserImpl p{"vec4<if>(2., 3., 4., 5.)"};
auto e = p.primary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("vec4<if>(2., 3., 4., 5.)");
auto e = p->primary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"vec4<f32> 2., 3., 4., 5.)"};
auto e = p.primary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("vec4<f32> 2., 3., 4., 5.)");
auto e = p->primary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"vec4<f32>(2., 3., 4., 5."};
auto e = p.primary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("vec4<f32>(2., 3., 4., 5.");
auto e = p->primary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"i32(if(a) {})"};
auto e = p.primary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("i32(if(a) {})");
auto e = p->primary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"true"};
auto e = p.primary_expression();
ASSERT_FALSE(p.has_error());
auto p = parser("true");
auto e = p->primary_expression();
ASSERT_FALSE(p->has_error());
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsInitializer());
ASSERT_TRUE(e->AsInitializer()->IsConstInitializer());
@ -149,44 +148,43 @@ TEST_F(ParserImplTest, PrimaryExpression_ConstLiteral_True) {
}
TEST_F(ParserImplTest, PrimaryExpression_ParenExpr) {
ParserImpl p{"(a == b)"};
auto e = p.primary_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("(a == b)");
auto e = p->primary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsRelational());
}
TEST_F(ParserImplTest, PrimaryExpression_ParenExpr_MissingRightParen) {
ParserImpl p{"(a == b"};
auto e = p.primary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("(a == b");
auto e = p->primary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: expected )");
EXPECT_EQ(p->error(), "1:8: expected )");
}
TEST_F(ParserImplTest, PrimaryExpression_ParenExpr_MissingExpr) {
ParserImpl p{"()"};
auto e = p.primary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("()");
auto e = p->primary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"(if (a) {})"};
auto e = p.primary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("(if (a) {})");
auto e = p->primary_expression();
ASSERT_TRUE(p->has_error());
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) {
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 e = p.primary_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("cast<f32>(1)");
auto e = p->primary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsCast());
@ -195,73 +193,70 @@ TEST_F(ParserImplTest, PrimaryExpression_Cast) {
ASSERT_TRUE(c->expr()->IsInitializer());
ASSERT_TRUE(c->expr()->AsInitializer()->IsConstInitializer());
TypeManager::Destroy();
}
TEST_F(ParserImplTest, PrimaryExpression_Cast_MissingGreaterThan) {
ParserImpl p{"cast<f32(1)"};
auto e = p.primary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("cast<f32(1)");
auto e = p->primary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"cast<>(1)"};
auto e = p.primary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("cast<>(1)");
auto e = p->primary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"cast<invalid>(1)"};
auto e = p.primary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("cast<invalid>(1)");
auto e = p->primary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"cast<f32>1)"};
auto e = p.primary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("cast<f32>1)");
auto e = p->primary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:10: expected (");
EXPECT_EQ(p->error(), "1:10: expected (");
}
TEST_F(ParserImplTest, PrimaryExpression_Cast_MissingRightParen) {
ParserImpl p{"cast<f32>(1"};
auto e = p.primary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("cast<f32>(1");
auto e = p->primary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:12: expected )");
EXPECT_EQ(p->error(), "1:12: expected )");
}
TEST_F(ParserImplTest, PrimaryExpression_Cast_MissingExpression) {
ParserImpl p{"cast<f32>()"};
auto e = p.primary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("cast<f32>()");
auto e = p->primary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"cast<f32>(if (a) {})"};
auto e = p.primary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("cast<f32>(if (a) {})");
auto e = p->primary_expression();
ASSERT_TRUE(p->has_error());
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) {
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 e = p.primary_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("as<f32>(1)");
auto e = p->primary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsAs());
@ -270,64 +265,62 @@ TEST_F(ParserImplTest, PrimaryExpression_As) {
ASSERT_TRUE(c->expr()->IsInitializer());
ASSERT_TRUE(c->expr()->AsInitializer()->IsConstInitializer());
TypeManager::Destroy();
}
TEST_F(ParserImplTest, PrimaryExpression_As_MissingGreaterThan) {
ParserImpl p{"as<f32(1)"};
auto e = p.primary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("as<f32(1)");
auto e = p->primary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"as<>(1)"};
auto e = p.primary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("as<>(1)");
auto e = p->primary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"as<invalid>(1)"};
auto e = p.primary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("as<invalid>(1)");
auto e = p->primary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"as<f32>1)"};
auto e = p.primary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("as<f32>1)");
auto e = p->primary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:8: expected (");
EXPECT_EQ(p->error(), "1:8: expected (");
}
TEST_F(ParserImplTest, PrimaryExpression_As_MissingRightParen) {
ParserImpl p{"as<f32>(1"};
auto e = p.primary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("as<f32>(1");
auto e = p->primary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p.error(), "1:10: expected )");
EXPECT_EQ(p->error(), "1:10: expected )");
}
TEST_F(ParserImplTest, PrimaryExpression_As_MissingExpression) {
ParserImpl p{"as<f32>()"};
auto e = p.primary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("as<f32>()");
auto e = p->primary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"as<f32>(if (a) {})"};
auto e = p.primary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("as<f32>(if (a) {})");
auto e = p->primary_expression();
ASSERT_TRUE(p->has_error());
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -15,12 +15,12 @@
#include "gtest/gtest.h"
#include "src/ast/storage_class.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint {
namespace reader {
namespace wgsl {
using ParserImplTest = testing::Test;
namespace {
struct StorageClassData {
const char* input;
@ -30,16 +30,41 @@ inline std::ostream& operator<<(std::ostream& out, StorageClassData data) {
out << std::string(data.input);
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) {
auto params = GetParam();
ParserImpl p{params.input};
auto p = parser(params.input);
auto sc = p.storage_class();
ASSERT_FALSE(p.has_error());
auto sc = p->storage_class();
ASSERT_FALSE(p->has_error());
EXPECT_EQ(sc, params.result);
auto t = p.next();
auto t = p->next();
EXPECT_TRUE(t.IsEof());
}
INSTANTIATE_TEST_SUITE_P(
@ -59,11 +84,11 @@ INSTANTIATE_TEST_SUITE_P(
StorageClassData{"function", ast::StorageClass::kFunction}));
TEST_F(ParserImplTest, StorageClass_NoMatch) {
ParserImpl p{"not-a-storage-class"};
auto sc = p.storage_class();
auto p = parser("not-a-storage-class");
auto sc = p->storage_class();
ASSERT_EQ(sc, ast::StorageClass::kNone);
auto t = p.next();
auto t = p->next();
EXPECT_TRUE(t.IsIdentifier());
EXPECT_EQ(t.to_str(), "not");
}

View File

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

View File

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

View File

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

View File

@ -15,12 +15,12 @@
#include "gtest/gtest.h"
#include "src/ast/struct_decoration.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint {
namespace reader {
namespace wgsl {
using ParserImplTest = testing::Test;
namespace {
struct StructDecorationData {
const char* input;
@ -30,16 +30,42 @@ inline std::ostream& operator<<(std::ostream& out, StructDecorationData data) {
out << std::string(data.input);
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) {
auto params = GetParam();
ParserImpl p{params.input};
auto p = parser(params.input);
auto deco = p.struct_decoration();
ASSERT_FALSE(p.has_error());
auto deco = p->struct_decoration();
ASSERT_FALSE(p->has_error());
EXPECT_EQ(deco, params.result);
auto t = p.next();
auto t = p->next();
EXPECT_TRUE(t.IsEof());
}
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
@ -48,11 +74,11 @@ INSTANTIATE_TEST_SUITE_P(ParserImplTest,
"block", ast::StructDecoration::kBlock}));
TEST_F(ParserImplTest, StructDecoration_NoMatch) {
ParserImpl p{"not-a-stage"};
auto deco = p.struct_decoration();
auto p = parser("not-a-stage");
auto deco = p->struct_decoration();
ASSERT_EQ(deco, ast::StructDecoration::kNone);
auto t = p.next();
auto t = p->next();
EXPECT_TRUE(t.IsIdentifier());
EXPECT_EQ(t.to_str(), "not");
}

View File

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

View File

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

View File

@ -16,37 +16,32 @@
#include "src/ast/struct_member_offset_decoration.h"
#include "src/ast/type/i32_type.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
#include "src/type_manager.h"
namespace tint {
namespace reader {
namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, StructMember_Parses) {
auto i32 =
TypeManager::Instance()->Get(std::make_unique<ast::type::I32Type>());
auto i32 = tm()->Get(std::make_unique<ast::type::I32Type>());
ParserImpl p{"a : i32;"};
auto m = p.struct_member();
ASSERT_FALSE(p.has_error());
auto p = parser("a : i32;");
auto m = p->struct_member();
ASSERT_FALSE(p->has_error());
ASSERT_NE(m, nullptr);
EXPECT_EQ(m->name(), "a");
EXPECT_EQ(m->type(), i32);
EXPECT_EQ(m->decorations().size(), 0);
TypeManager::Destroy();
}
TEST_F(ParserImplTest, StructMember_ParsesWithDecoration) {
auto i32 =
TypeManager::Instance()->Get(std::make_unique<ast::type::I32Type>());
auto i32 = tm()->Get(std::make_unique<ast::type::I32Type>());
ParserImpl p{"[[offset 2]] a : i32;"};
auto m = p.struct_member();
ASSERT_FALSE(p.has_error());
auto p = parser("[[offset 2]] a : i32;");
auto m = p->struct_member();
ASSERT_FALSE(p->has_error());
ASSERT_NE(m, nullptr);
EXPECT_EQ(m->name(), "a");
@ -54,32 +49,30 @@ TEST_F(ParserImplTest, StructMember_ParsesWithDecoration) {
EXPECT_EQ(m->decorations().size(), 1);
EXPECT_TRUE(m->decorations()[0]->IsOffset());
EXPECT_EQ(m->decorations()[0]->AsOffset()->offset(), 2);
TypeManager::Destroy();
}
TEST_F(ParserImplTest, StructMember_InvalidDecoration) {
ParserImpl p{"[[offset nan]] a : i32;"};
auto m = p.struct_member();
ASSERT_TRUE(p.has_error());
auto p = parser("[[offset nan]] a : i32;");
auto m = p->struct_member();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"[[offset 4]] a : B;"};
auto m = p.struct_member();
ASSERT_TRUE(p.has_error());
auto p = parser("[[offset 4]] a : B;");
auto m = p->struct_member();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"a : i32"};
auto m = p.struct_member();
ASSERT_TRUE(p.has_error());
auto p = parser("a : i32");
auto m = p->struct_member();
ASSERT_TRUE(p->has_error());
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

View File

@ -15,17 +15,16 @@
#include "gtest/gtest.h"
#include "src/ast/case_statement.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint {
namespace reader {
namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, SwitchBody_Case) {
ParserImpl p{"case 1: { a = 4; }"};
auto e = p.switch_body();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("case 1: { a = 4; }");
auto e = p->switch_body();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsCase());
EXPECT_FALSE(e->IsDefault());
@ -34,57 +33,57 @@ TEST_F(ParserImplTest, SwitchBody_Case) {
}
TEST_F(ParserImplTest, SwitchBody_Case_InvalidConstLiteral) {
ParserImpl p{"case a == 4: { a = 4; }"};
auto e = p.switch_body();
ASSERT_TRUE(p.has_error());
auto p = parser("case a == 4: { a = 4; }");
auto e = p->switch_body();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"case: { a = 4; }"};
auto e = p.switch_body();
ASSERT_TRUE(p.has_error());
auto p = parser("case: { a = 4; }");
auto e = p->switch_body();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"case 1 { a = 4; }"};
auto e = p.switch_body();
ASSERT_TRUE(p.has_error());
auto p = parser("case 1 { a = 4; }");
auto e = p->switch_body();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"case 1: a = 4; }"};
auto e = p.switch_body();
ASSERT_TRUE(p.has_error());
auto p = parser("case 1: a = 4; }");
auto e = p->switch_body();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"case 1: { a = 4; "};
auto e = p.switch_body();
ASSERT_TRUE(p.has_error());
auto p = parser("case 1: { a = 4; ");
auto e = p->switch_body();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"case 1: { fn main() -> void {} }"};
auto e = p.switch_body();
ASSERT_TRUE(p.has_error());
auto p = parser("case 1: { fn main() -> void {} }");
auto e = p->switch_body();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"default: { a = 4; }"};
auto e = p.switch_body();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("default: { a = 4; }");
auto e = p->switch_body();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsCase());
EXPECT_TRUE(e->IsDefault());
@ -93,35 +92,35 @@ TEST_F(ParserImplTest, SwitchBody_Default) {
}
TEST_F(ParserImplTest, SwitchBody_Default_MissingColon) {
ParserImpl p{"default { a = 4; }"};
auto e = p.switch_body();
ASSERT_TRUE(p.has_error());
auto p = parser("default { a = 4; }");
auto e = p->switch_body();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"default: a = 4; }"};
auto e = p.switch_body();
ASSERT_TRUE(p.has_error());
auto p = parser("default: a = 4; }");
auto e = p->switch_body();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"default: { a = 4; "};
auto e = p.switch_body();
ASSERT_TRUE(p.has_error());
auto p = parser("default: { a = 4; ");
auto e = p->switch_body();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"default: { fn main() -> void {} }"};
auto e = p.switch_body();
ASSERT_TRUE(p.has_error());
auto p = parser("default: { fn main() -> void {} }");
auto e = p->switch_body();
ASSERT_TRUE(p->has_error());
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

View File

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

View File

@ -16,20 +16,19 @@
#include "gtest/gtest.h"
#include "src/ast/type/i32_type.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint {
namespace reader {
namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, Empty) {
ParserImpl p{""};
ASSERT_TRUE(p.Parse()) << p.error();
auto p = parser("");
ASSERT_TRUE(p->Parse()) << p->error();
}
TEST_F(ParserImplTest, DISABLED_Parses) {
ParserImpl p{R"(
auto p = parser(R"(
import "GLSL.std.430" as glsl;
[[location 0]] var<out> gl_FragColor : vec4<f32>;
@ -37,41 +36,41 @@ import "GLSL.std.430" as glsl;
fn main() -> void {
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());
// TODO(dsinclair) check rest of AST ...
}
TEST_F(ParserImplTest, DISABLED_HandlesError) {
ParserImpl p{R"(
auto p = parser(R"(
import "GLSL.std.430" as glsl;
fn main() -> { # missing return type
return;
})"};
})");
ASSERT_FALSE(p.Parse());
ASSERT_TRUE(p.has_error());
EXPECT_EQ(p.error(), "4:15: missing return type for function");
ASSERT_FALSE(p->Parse());
ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "4:15: missing return type for function");
}
TEST_F(ParserImplTest, GetRegisteredType) {
ParserImpl p{""};
auto p = parser("");
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_EQ(alias, &i32);
}
TEST_F(ParserImplTest, GetUnregisteredType) {
ParserImpl p{""};
auto alias = p.get_alias("my_alias");
auto p = parser("");
auto alias = p->get_alias("my_alias");
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/struct_type.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
#include "src/type_manager.h"
namespace tint {
namespace reader {
namespace wgsl {
using ParserImplTest = testing::Test;
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 t = p.type_alias();
ASSERT_FALSE(p.has_error());
auto p = parser("type a = i32");
auto t = p->type_alias();
ASSERT_FALSE(p->has_error());
ASSERT_NE(t, nullptr);
ASSERT_TRUE(t->type()->IsI32());
ASSERT_EQ(t->type(), i32);
TypeManager::Destroy();
}
TEST_F(ParserImplTest, TypeDecl_ParsesStruct) {
ParserImpl p{"type a = struct { b: i32; c: f32;}"};
auto t = p.type_alias();
ASSERT_FALSE(p.has_error());
auto p = parser("type a = struct { b: i32; c: f32;}");
auto t = p->type_alias();
ASSERT_FALSE(p->has_error());
ASSERT_NE(t, nullptr);
EXPECT_EQ(t->name(), "a");
ASSERT_TRUE(t->type()->IsStruct());
@ -52,43 +48,43 @@ TEST_F(ParserImplTest, TypeDecl_ParsesStruct) {
}
TEST_F(ParserImplTest, TypeDecl_MissingIdent) {
ParserImpl p{"type = i32"};
auto t = p.type_alias();
ASSERT_TRUE(p.has_error());
auto p = parser("type = i32");
auto t = p->type_alias();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"type 123 = i32"};
auto t = p.type_alias();
ASSERT_TRUE(p.has_error());
auto p = parser("type 123 = i32");
auto t = p->type_alias();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"type a i32"};
auto t = p.type_alias();
ASSERT_TRUE(p.has_error());
auto p = parser("type a i32");
auto t = p->type_alias();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"type a = B"};
auto t = p.type_alias();
ASSERT_TRUE(p.has_error());
auto p = parser("type a = B");
auto t = p->type_alias();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"type a = [[block]] {}"};
auto t = p.type_alias();
ASSERT_TRUE(p.has_error());
auto p = parser("type a = [[block]] {}");
auto t = p->type_alias();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(t, nullptr);
EXPECT_EQ(p.error(), "1:20: missing struct declaration");
EXPECT_EQ(p->error(), "1:20: missing struct declaration");
}
} // namespace wgsl

View File

@ -24,33 +24,31 @@
#include "src/ast/type/u32_type.h"
#include "src/ast/type/vector_type.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
#include "src/type_manager.h"
namespace tint {
namespace reader {
namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, TypeDecl_Invalid) {
ParserImpl p{"1234"};
auto t = p.type_decl();
auto p = parser("1234");
auto t = p->type_decl();
EXPECT_EQ(t, nullptr);
EXPECT_FALSE(p.has_error());
EXPECT_FALSE(p->has_error());
}
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.
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);
EXPECT_EQ(t, alias_type);
ASSERT_TRUE(t->IsAlias());
@ -58,73 +56,59 @@ TEST_F(ParserImplTest, TypeDecl_Identifier) {
auto alias = t->AsAlias();
EXPECT_EQ(alias->name(), "A");
EXPECT_EQ(alias->type(), int_type);
TypeManager::Destroy();
}
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);
EXPECT_TRUE(p.has_error());
EXPECT_EQ(p.error(), "1:1: unknown type alias 'B'");
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:1: unknown type alias 'B'");
}
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);
EXPECT_EQ(t, bool_type);
ASSERT_TRUE(t->IsBool());
TypeManager::Destroy();
}
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);
EXPECT_EQ(t, float_type);
ASSERT_TRUE(t->IsF32());
TypeManager::Destroy();
}
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);
EXPECT_EQ(t, int_type);
ASSERT_TRUE(t->IsI32());
TypeManager::Destroy();
}
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);
EXPECT_EQ(t, uint_type);
ASSERT_TRUE(t->IsU32());
TypeManager::Destroy();
}
struct VecData {
@ -135,13 +119,35 @@ inline std::ostream& operator<<(std::ostream& out, VecData data) {
out << std::string(data.input);
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) {
auto params = GetParam();
ParserImpl p{params.input};
auto t = p.type_decl();
auto p = parser(params.input);
auto t = p->type_decl();
ASSERT_NE(t, nullptr);
ASSERT_FALSE(p.has_error());
ASSERT_FALSE(p->has_error());
EXPECT_TRUE(t->IsVector());
EXPECT_EQ(t->AsVector()->size(), params.count);
}
@ -151,14 +157,36 @@ INSTANTIATE_TEST_SUITE_P(ParserImplTest,
VecData{"vec3<f32>", 3},
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) {
auto params = GetParam();
ParserImpl p{params.input};
auto t = p.type_decl();
auto p = parser(params.input);
auto t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error());
ASSERT_EQ(p.error(), "1:9: missing > for vector");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:9: missing > for vector");
}
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
VecMissingGreaterThanTest,
@ -166,14 +194,36 @@ INSTANTIATE_TEST_SUITE_P(ParserImplTest,
VecData{"vec3<f32", 3},
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) {
auto params = GetParam();
ParserImpl p{params.input};
auto t = p.type_decl();
auto p = parser(params.input);
auto t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error());
ASSERT_EQ(p.error(), "1:5: missing < for vector");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:5: missing < for vector");
}
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
VecMissingLessThanTest,
@ -181,14 +231,36 @@ INSTANTIATE_TEST_SUITE_P(ParserImplTest,
VecData{"vec3", 3},
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) {
auto params = GetParam();
ParserImpl p{params.input};
auto t = p.type_decl();
auto p = parser(params.input);
auto t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error());
ASSERT_EQ(p.error(), "1:6: unknown type alias 'unknown'");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:6: unknown type alias 'unknown'");
}
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
VecBadType,
@ -196,14 +268,36 @@ INSTANTIATE_TEST_SUITE_P(ParserImplTest,
VecData{"vec3<unknown", 3},
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) {
auto params = GetParam();
ParserImpl p{params.input};
auto t = p.type_decl();
auto p = parser(params.input);
auto t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error());
ASSERT_EQ(p.error(), "1:6: unable to determine subtype for vector");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:6: unable to determine subtype for vector");
}
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
VecMissingType,
@ -212,10 +306,10 @@ INSTANTIATE_TEST_SUITE_P(ParserImplTest,
VecData{"vec4<>", 4}));
TEST_F(ParserImplTest, TypeDecl_Ptr) {
ParserImpl p{"ptr<function, f32>"};
auto t = p.type_decl();
ASSERT_NE(t, nullptr) << p.error();
ASSERT_FALSE(p.has_error());
auto p = parser("ptr<function, f32>");
auto t = p->type_decl();
ASSERT_NE(t, nullptr) << p->error();
ASSERT_FALSE(p->has_error());
ASSERT_TRUE(t->IsPointer());
auto ptr = t->AsPointer();
@ -224,10 +318,10 @@ TEST_F(ParserImplTest, TypeDecl_Ptr) {
}
TEST_F(ParserImplTest, TypeDecl_Ptr_ToVec) {
ParserImpl p{"ptr<function, vec2<f32>>"};
auto t = p.type_decl();
ASSERT_NE(t, nullptr) << p.error();
ASSERT_FALSE(p.has_error());
auto p = parser("ptr<function, vec2<f32>>");
auto t = p->type_decl();
ASSERT_NE(t, nullptr) << p->error();
ASSERT_FALSE(p->has_error());
ASSERT_TRUE(t->IsPointer());
auto ptr = t->AsPointer();
@ -240,74 +334,74 @@ TEST_F(ParserImplTest, TypeDecl_Ptr_ToVec) {
}
TEST_F(ParserImplTest, TypeDecl_Ptr_MissingLessThan) {
ParserImpl p{"ptr private, f32>"};
auto t = p.type_decl();
auto p = parser("ptr private, f32>");
auto t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error());
ASSERT_EQ(p.error(), "1:5: missing < for ptr declaration");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:5: missing < for ptr declaration");
}
TEST_F(ParserImplTest, TypeDecl_Ptr_MissingGreaterThan) {
ParserImpl p{"ptr<function, f32"};
auto t = p.type_decl();
auto p = parser("ptr<function, f32");
auto t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error());
ASSERT_EQ(p.error(), "1:18: missing > for ptr declaration");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:18: missing > for ptr declaration");
}
TEST_F(ParserImplTest, TypeDecl_Ptr_MissingComma) {
ParserImpl p{"ptr<function f32>"};
auto t = p.type_decl();
auto p = parser("ptr<function f32>");
auto t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error());
ASSERT_EQ(p.error(), "1:14: missing , for ptr declaration");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:14: missing , for ptr declaration");
}
TEST_F(ParserImplTest, TypeDecl_Ptr_MissingStorageClass) {
ParserImpl p{"ptr<, f32>"};
auto t = p.type_decl();
auto p = parser("ptr<, f32>");
auto t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error());
ASSERT_EQ(p.error(), "1:5: missing storage class for ptr declaration");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:5: missing storage class for ptr declaration");
}
TEST_F(ParserImplTest, TypeDecl_Ptr_MissingParams) {
ParserImpl p{"ptr<>"};
auto t = p.type_decl();
auto p = parser("ptr<>");
auto t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error());
ASSERT_EQ(p.error(), "1:5: missing storage class for ptr declaration");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:5: missing storage class for ptr declaration");
}
TEST_F(ParserImplTest, TypeDecl_Ptr_MissingType) {
ParserImpl p{"ptr<function,>"};
auto t = p.type_decl();
auto p = parser("ptr<function,>");
auto t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error());
ASSERT_EQ(p.error(), "1:14: missing type for ptr declaration");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:14: missing type for ptr declaration");
}
TEST_F(ParserImplTest, TypeDecl_Ptr_BadStorageClass) {
ParserImpl p{"ptr<unknown, f32>"};
auto t = p.type_decl();
auto p = parser("ptr<unknown, f32>");
auto t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error());
ASSERT_EQ(p.error(), "1:5: missing storage class for ptr declaration");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:5: missing storage class for ptr declaration");
}
TEST_F(ParserImplTest, TypeDecl_Ptr_BadType) {
ParserImpl p{"ptr<function, unknown>"};
auto t = p.type_decl();
auto p = parser("ptr<function, unknown>");
auto t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error());
ASSERT_EQ(p.error(), "1:15: unknown type alias 'unknown'");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:15: unknown type alias 'unknown'");
}
TEST_F(ParserImplTest, TypeDecl_Array) {
ParserImpl p{"array<f32, 5>"};
auto t = p.type_decl();
auto p = parser("array<f32, 5>");
auto t = p->type_decl();
ASSERT_NE(t, nullptr);
ASSERT_FALSE(p.has_error());
ASSERT_FALSE(p->has_error());
ASSERT_TRUE(t->IsArray());
auto a = t->AsArray();
@ -317,10 +411,10 @@ TEST_F(ParserImplTest, TypeDecl_Array) {
}
TEST_F(ParserImplTest, TypeDecl_Array_Runtime) {
ParserImpl p{"array<u32>"};
auto t = p.type_decl();
auto p = parser("array<u32>");
auto t = p->type_decl();
ASSERT_NE(t, nullptr);
ASSERT_FALSE(p.has_error());
ASSERT_FALSE(p->has_error());
ASSERT_TRUE(t->IsArray());
auto a = t->AsArray();
@ -329,59 +423,59 @@ TEST_F(ParserImplTest, TypeDecl_Array_Runtime) {
}
TEST_F(ParserImplTest, TypeDecl_Array_BadType) {
ParserImpl p{"array<unknown, 3>"};
auto t = p.type_decl();
auto p = parser("array<unknown, 3>");
auto t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error());
ASSERT_EQ(p.error(), "1:7: unknown type alias 'unknown'");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:7: unknown type alias 'unknown'");
}
TEST_F(ParserImplTest, TypeDecl_Array_ZeroSize) {
ParserImpl p{"array<f32, 0>"};
auto t = p.type_decl();
auto p = parser("array<f32, 0>");
auto t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error());
ASSERT_EQ(p.error(), "1:12: invalid size for array declaration");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:12: invalid size for array declaration");
}
TEST_F(ParserImplTest, TypeDecl_Array_NegativeSize) {
ParserImpl p{"array<f32, -1>"};
auto t = p.type_decl();
auto p = parser("array<f32, -1>");
auto t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error());
ASSERT_EQ(p.error(), "1:12: invalid size for array declaration");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:12: invalid size for array declaration");
}
TEST_F(ParserImplTest, TypeDecl_Array_BadSize) {
ParserImpl p{"array<f32, invalid>"};
auto t = p.type_decl();
auto p = parser("array<f32, invalid>");
auto t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error());
ASSERT_EQ(p.error(), "1:12: missing size of array declaration");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:12: missing size of array declaration");
}
TEST_F(ParserImplTest, TypeDecl_Array_MissingLessThan) {
ParserImpl p{"array f32>"};
auto t = p.type_decl();
auto p = parser("array f32>");
auto t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error());
ASSERT_EQ(p.error(), "1:7: missing < for array declaration");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:7: missing < for array declaration");
}
TEST_F(ParserImplTest, TypeDecl_Array_MissingGreaterThan) {
ParserImpl p{"array<f32"};
auto t = p.type_decl();
auto p = parser("array<f32");
auto t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error());
ASSERT_EQ(p.error(), "1:10: missing > for array declaration");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:10: missing > for array declaration");
}
TEST_F(ParserImplTest, TypeDecl_Array_MissingComma) {
ParserImpl p{"array<f32 3>"};
auto t = p.type_decl();
auto p = parser("array<f32 3>");
auto t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error());
ASSERT_EQ(p.error(), "1:11: missing > for array declaration");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:11: missing > for array declaration");
}
struct MatrixData {
@ -393,13 +487,35 @@ inline std::ostream& operator<<(std::ostream& out, MatrixData data) {
out << std::string(data.input);
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) {
auto params = GetParam();
ParserImpl p{params.input};
auto t = p.type_decl();
auto p = parser(params.input);
auto t = p->type_decl();
ASSERT_NE(t, nullptr);
ASSERT_FALSE(p.has_error());
ASSERT_FALSE(p->has_error());
EXPECT_TRUE(t->IsMatrix());
auto mat = t->AsMatrix();
EXPECT_EQ(mat->rows(), params.rows);
@ -417,14 +533,35 @@ INSTANTIATE_TEST_SUITE_P(ParserImplTest,
MatrixData{"mat4x3<f32>", 4, 3},
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) {
auto params = GetParam();
ParserImpl p{params.input};
auto t = p.type_decl();
auto p = parser(params.input);
auto t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error());
ASSERT_EQ(p.error(), "1:11: missing > for matrix");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:11: missing > for matrix");
}
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
MatrixMissingGreaterThanTest,
@ -438,14 +575,35 @@ INSTANTIATE_TEST_SUITE_P(ParserImplTest,
MatrixData{"mat4x3<f32", 4, 3},
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) {
auto params = GetParam();
ParserImpl p{params.input};
auto t = p.type_decl();
auto p = parser(params.input);
auto t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error());
ASSERT_EQ(p.error(), "1:8: missing < for matrix");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:8: missing < for matrix");
}
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
MatrixMissingLessThanTest,
@ -459,14 +617,35 @@ INSTANTIATE_TEST_SUITE_P(ParserImplTest,
MatrixData{"mat4x3 f32>", 4, 3},
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) {
auto params = GetParam();
ParserImpl p{params.input};
auto t = p.type_decl();
auto p = parser(params.input);
auto t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error());
ASSERT_EQ(p.error(), "1:8: unknown type alias 'unknown'");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:8: unknown type alias 'unknown'");
}
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
MatrixBadType,
@ -480,14 +659,35 @@ INSTANTIATE_TEST_SUITE_P(ParserImplTest,
MatrixData{"mat4x3<unknown>", 4, 3},
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) {
auto params = GetParam();
ParserImpl p{params.input};
auto t = p.type_decl();
auto p = parser(params.input);
auto t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p.has_error());
ASSERT_EQ(p.error(), "1:8: unable to determine subtype for matrix");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:8: unable to determine subtype for matrix");
}
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
MatrixMissingType,

View File

@ -21,17 +21,16 @@
#include "src/ast/unary_method_expression.h"
#include "src/ast/unary_op_expression.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint {
namespace reader {
namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, UnaryExpression_Postix) {
ParserImpl p{"a[2]"};
auto e = p.unary_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("a[2]");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsArrayAccessor());
@ -49,9 +48,9 @@ TEST_F(ParserImplTest, UnaryExpression_Postix) {
}
TEST_F(ParserImplTest, UnaryExpression_Minus) {
ParserImpl p{"- 1"};
auto e = p.unary_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("- 1");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryOp());
@ -67,17 +66,17 @@ TEST_F(ParserImplTest, UnaryExpression_Minus) {
}
TEST_F(ParserImplTest, UnaryExpression_Minus_InvalidRHS) {
ParserImpl p{"-if(a) {}"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("-if(a) {}");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"!1"};
auto e = p.unary_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("!1");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryOp());
@ -93,17 +92,17 @@ TEST_F(ParserImplTest, UnaryExpression_Bang) {
}
TEST_F(ParserImplTest, UnaryExpression_Bang_InvalidRHS) {
ParserImpl p{"!if (a) {}"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("!if (a) {}");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"any(a)"};
auto e = p.unary_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("any(a)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryMethod());
@ -117,41 +116,41 @@ TEST_F(ParserImplTest, UnaryExpression_Any) {
}
TEST_F(ParserImplTest, UnaryExpression_Any_MissingParenLeft) {
ParserImpl p{"any a)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("any a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"any(a"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("any(a");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"any()"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("any()");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"any(123)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("any(123)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"all(a)"};
auto e = p.unary_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("all(a)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryMethod());
@ -165,41 +164,41 @@ TEST_F(ParserImplTest, UnaryExpression_All) {
}
TEST_F(ParserImplTest, UnaryExpression_All_MissingParenLeft) {
ParserImpl p{"all a)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("all a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"all(a"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("all(a");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"all()"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("all()");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"all(123)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("all(123)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"is_nan(a)"};
auto e = p.unary_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("is_nan(a)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryMethod());
@ -213,41 +212,41 @@ TEST_F(ParserImplTest, UnaryExpression_IsNan) {
}
TEST_F(ParserImplTest, UnaryExpression_IsNan_MissingParenLeft) {
ParserImpl p{"is_nan a)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("is_nan a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"is_nan(a"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("is_nan(a");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"is_nan()"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("is_nan()");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"is_nan(123)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("is_nan(123)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"is_inf(a)"};
auto e = p.unary_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("is_inf(a)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryMethod());
@ -261,41 +260,41 @@ TEST_F(ParserImplTest, UnaryExpression_IsInf) {
}
TEST_F(ParserImplTest, UnaryExpression_IsInf_MissingParenLeft) {
ParserImpl p{"is_inf a)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("is_inf a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"is_inf(a"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("is_inf(a");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"is_inf()"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("is_inf()");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"is_inf(123)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("is_inf(123)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"is_finite(a)"};
auto e = p.unary_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("is_finite(a)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryMethod());
@ -309,41 +308,41 @@ TEST_F(ParserImplTest, UnaryExpression_IsFinite) {
}
TEST_F(ParserImplTest, UnaryExpression_IsFinite_MissingParenLeft) {
ParserImpl p{"is_finite a)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("is_finite a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"is_finite(a"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("is_finite(a");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"is_finite()"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("is_finite()");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"is_finite(123)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("is_finite(123)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"is_normal(a)"};
auto e = p.unary_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("is_normal(a)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryMethod());
@ -357,41 +356,41 @@ TEST_F(ParserImplTest, UnaryExpression_IsNormal) {
}
TEST_F(ParserImplTest, UnaryExpression_IsNormal_MissingParenLeft) {
ParserImpl p{"is_normal a)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("is_normal a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"is_normal(a"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("is_normal(a");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"is_normal()"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("is_normal()");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"is_normal(123)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("is_normal(123)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"dot(a, b)"};
auto e = p.unary_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("dot(a, b)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryMethod());
@ -410,65 +409,65 @@ TEST_F(ParserImplTest, UnaryExpression_Dot) {
}
TEST_F(ParserImplTest, UnaryExpression_Dot_MissingParenLeft) {
ParserImpl p{"dot a, b)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("dot a, b)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"dot(a, b"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("dot(a, b");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"dot(, a)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("dot(, a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"dot(a, )"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("dot(a, )");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"dot(a b)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("dot(a b)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"dot(123, b)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("dot(123, b)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"dot(a, 123)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("dot(a, 123)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"outer_product(a, b)"};
auto e = p.unary_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("outer_product(a, b)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryMethod());
@ -487,65 +486,65 @@ TEST_F(ParserImplTest, UnaryExpression_OuterProduct) {
}
TEST_F(ParserImplTest, UnaryExpression_OuterProduct_MissingParenLeft) {
ParserImpl p{"outer_product a, b)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("outer_product a, b)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"outer_product(a, b"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("outer_product(a, b");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"outer_product(, b)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("outer_product(, b)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"outer_product(a, )"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("outer_product(a, )");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"outer_product(a b)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("outer_product(a b)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"outer_product(123, b)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("outer_product(123, b)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"outer_product(a, 123)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("outer_product(a, 123)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"dpdx(a)"};
auto e = p.unary_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("dpdx(a)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryDerivative());
@ -561,9 +560,9 @@ TEST_F(ParserImplTest, UnaryExpression_Dpdx_NoModifier) {
}
TEST_F(ParserImplTest, UnaryExpression_Dpdx_WithModifier) {
ParserImpl p{"dpdx<coarse>(a)"};
auto e = p.unary_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("dpdx<coarse>(a)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryDerivative());
@ -579,73 +578,73 @@ TEST_F(ParserImplTest, UnaryExpression_Dpdx_WithModifier) {
}
TEST_F(ParserImplTest, UnaryExpression_Dpdx_MissingLessThan) {
ParserImpl p{"dpdx coarse>(a)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("dpdx coarse>(a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"dpdx<invalid>(a)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("dpdx<invalid>(a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"dpdx coarse>(a)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("dpdx coarse>(a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"dpdx<coarse (a)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("dpdx<coarse (a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"dpdx<coarse>a)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("dpdx<coarse>a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"dpdx<coarse>(a"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("dpdx<coarse>(a");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"dpdx<coarse>()"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("dpdx<coarse>()");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"dpdx<coarse>(12345)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("dpdx<coarse>(12345)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"dpdy(a)"};
auto e = p.unary_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("dpdy(a)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryDerivative());
@ -661,9 +660,9 @@ TEST_F(ParserImplTest, UnaryExpression_Dpdy_NoModifier) {
}
TEST_F(ParserImplTest, UnaryExpression_Dpdy_WithModifier) {
ParserImpl p{"dpdy<fine>(a)"};
auto e = p.unary_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("dpdy<fine>(a)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryDerivative());
@ -679,73 +678,73 @@ TEST_F(ParserImplTest, UnaryExpression_Dpdy_WithModifier) {
}
TEST_F(ParserImplTest, UnaryExpression_Dpdy_MissingLessThan) {
ParserImpl p{"dpdy coarse>(a)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("dpdy coarse>(a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"dpdy<invalid>(a)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("dpdy<invalid>(a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"dpdy coarse>(a)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("dpdy coarse>(a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"dpdy<coarse (a)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("dpdy<coarse (a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"dpdy<coarse>a)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("dpdy<coarse>a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"dpdy<coarse>(a"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("dpdy<coarse>(a");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"dpdy<coarse>()"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("dpdy<coarse>()");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"dpdy<coarse>(12345)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("dpdy<coarse>(12345)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"fwidth(a)"};
auto e = p.unary_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("fwidth(a)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryDerivative());
@ -761,9 +760,9 @@ TEST_F(ParserImplTest, UnaryExpression_Fwidth_NoModifier) {
}
TEST_F(ParserImplTest, UnaryExpression_Fwidth_WithModifier) {
ParserImpl p{"fwidth<coarse>(a)"};
auto e = p.unary_expression();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("fwidth<coarse>(a)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryDerivative());
@ -779,67 +778,67 @@ TEST_F(ParserImplTest, UnaryExpression_Fwidth_WithModifier) {
}
TEST_F(ParserImplTest, UnaryExpression_Fwidth_MissingLessThan) {
ParserImpl p{"fwidth coarse>(a)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("fwidth coarse>(a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"fwidth<invalid>(a)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("fwidth<invalid>(a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"fwidth coarse>(a)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("fwidth coarse>(a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"fwidth<coarse (a)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("fwidth<coarse (a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"fwidth<coarse>a)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("fwidth<coarse>a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"fwidth<coarse>(a"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("fwidth<coarse>(a");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"fwidth<coarse>()"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("fwidth<coarse>()");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"fwidth<coarse>(12345)"};
auto e = p.unary_expression();
ASSERT_TRUE(p.has_error());
auto p = parser("fwidth<coarse>(12345)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
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 reader

View File

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

View File

@ -15,17 +15,16 @@
#include "gtest/gtest.h"
#include "src/ast/variable.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint {
namespace reader {
namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, VariableDecl_Parses) {
ParserImpl p{"var my_var : f32"};
auto var = p.variable_decl();
ASSERT_FALSE(p.has_error());
auto p = parser("var my_var : f32");
auto var = p->variable_decl();
ASSERT_FALSE(p->has_error());
ASSERT_NE(var, nullptr);
ASSERT_EQ(var->name(), "my_var");
ASSERT_NE(var->type(), nullptr);
@ -35,27 +34,27 @@ TEST_F(ParserImplTest, VariableDecl_Parses) {
}
TEST_F(ParserImplTest, VariableDecl_MissingVar) {
ParserImpl p{"my_var : f32"};
auto v = p.variable_decl();
auto p = parser("my_var : f32");
auto v = p->variable_decl();
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());
}
TEST_F(ParserImplTest, VariableDecl_InvalidIdentDecl) {
ParserImpl p{"var my_var f32"};
auto v = p.variable_decl();
ASSERT_TRUE(p.has_error());
auto p = parser("var my_var f32");
auto v = p->variable_decl();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"var<private> my_var : f32"};
auto v = p.variable_decl();
ASSERT_FALSE(p.has_error());
auto p = parser("var<private> my_var : f32");
auto v = p->variable_decl();
ASSERT_FALSE(p->has_error());
ASSERT_NE(v, nullptr);
EXPECT_EQ(v->name(), "my_var");
EXPECT_TRUE(v->type()->IsF32());
@ -63,11 +62,11 @@ TEST_F(ParserImplTest, VariableDecl_WithStorageClass) {
}
TEST_F(ParserImplTest, VariableDecl_InvalidStorageClass) {
ParserImpl p{"var<unknown> my_var : f32"};
auto v = p.variable_decl();
ASSERT_TRUE(p.has_error());
auto p = parser("var<unknown> my_var : f32");
auto v = p->variable_decl();
ASSERT_TRUE(p->has_error());
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

View File

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

View File

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

View File

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

View File

@ -16,17 +16,16 @@
#include "src/ast/statement.h"
#include "src/ast/variable_statement.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint {
namespace reader {
namespace wgsl {
using ParserImplTest = testing::Test;
TEST_F(ParserImplTest, VariableStmt_VariableDecl) {
ParserImpl p{"var a : i32;"};
auto e = p.variable_stmt();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("var a : i32;");
auto e = p->variable_stmt();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsVariable());
ASSERT_NE(e->variable(), nullptr);
@ -36,9 +35,9 @@ TEST_F(ParserImplTest, VariableStmt_VariableDecl) {
}
TEST_F(ParserImplTest, VariableStmt_VariableDecl_WithInit) {
ParserImpl p{"var a : i32 = 1;"};
auto e = p.variable_stmt();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("var a : i32 = 1;");
auto e = p->variable_stmt();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsVariable());
ASSERT_NE(e->variable(), nullptr);
@ -49,59 +48,59 @@ TEST_F(ParserImplTest, VariableStmt_VariableDecl_WithInit) {
}
TEST_F(ParserImplTest, VariableStmt_VariableDecl_Invalid) {
ParserImpl p{"var a : invalid;"};
auto e = p.variable_stmt();
ASSERT_TRUE(p.has_error());
auto p = parser("var a : invalid;");
auto e = p->variable_stmt();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"var a : i32 = if(a) {}"};
auto e = p.variable_stmt();
ASSERT_TRUE(p.has_error());
auto p = parser("var a : i32 = if(a) {}");
auto e = p->variable_stmt();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"const a : i32 = 1"};
auto e = p.variable_stmt();
ASSERT_FALSE(p.has_error()) << p.error();
auto p = parser("const a : i32 = 1");
auto e = p->variable_stmt();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsVariable());
}
TEST_F(ParserImplTest, VariableStmt_Const_InvalidVarIdent) {
ParserImpl p{"const a : invalid = 1"};
auto e = p.variable_stmt();
ASSERT_TRUE(p.has_error());
auto p = parser("const a : invalid = 1");
auto e = p->variable_stmt();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"const a : i32 1"};
auto e = p.variable_stmt();
ASSERT_TRUE(p.has_error());
auto p = parser("const a : i32 1");
auto e = p->variable_stmt();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"const a : i32 ="};
auto e = p.variable_stmt();
ASSERT_TRUE(p.has_error());
auto p = parser("const a : i32 =");
auto e = p->variable_stmt();
ASSERT_TRUE(p->has_error());
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) {
ParserImpl p{"const a : i32 = if (a) {}"};
auto e = p.variable_stmt();
ASSERT_TRUE(p.has_error());
auto p = parser("const a : i32 = if (a) {}");
auto e = p->variable_stmt();
ASSERT_TRUE(p->has_error());
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

View File

@ -15,12 +15,12 @@
#include "gtest/gtest.h"
#include "src/ast/storage_class.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint {
namespace reader {
namespace wgsl {
using ParserImplTest = testing::Test;
namespace {
struct VariableStorageData {
const char* input;
@ -30,16 +30,41 @@ inline std::ostream& operator<<(std::ostream& out, VariableStorageData data) {
out << std::string(data.input);
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) {
auto params = GetParam();
ParserImpl p{std::string("<") + params.input + ">"};
auto p = parser(std::string("<") + params.input + ">");
auto sc = p.variable_storage_decoration();
ASSERT_FALSE(p.has_error());
auto sc = p->variable_storage_decoration();
ASSERT_FALSE(p->has_error());
EXPECT_EQ(sc, params.result);
auto t = p.next();
auto t = p->next();
EXPECT_TRUE(t.IsEof());
}
INSTANTIATE_TEST_SUITE_P(
@ -60,37 +85,37 @@ INSTANTIATE_TEST_SUITE_P(
VariableStorageData{"function", ast::StorageClass::kFunction}));
TEST_F(ParserImplTest, VariableStorageDecoration_NoMatch) {
ParserImpl p{"<not-a-storage-class>"};
auto sc = p.variable_storage_decoration();
auto p = parser("<not-a-storage-class>");
auto sc = p->variable_storage_decoration();
ASSERT_EQ(sc, ast::StorageClass::kNone);
ASSERT_TRUE(p.has_error());
ASSERT_EQ(p.error(), "1:2: invalid storage class for variable decoration");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:2: invalid storage class for variable decoration");
}
TEST_F(ParserImplTest, VariableStorageDecoration_Empty) {
ParserImpl p{"<>"};
auto sc = p.variable_storage_decoration();
auto p = parser("<>");
auto sc = p->variable_storage_decoration();
ASSERT_EQ(sc, ast::StorageClass::kNone);
ASSERT_TRUE(p.has_error());
ASSERT_EQ(p.error(), "1:2: invalid storage class for variable decoration");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:2: invalid storage class for variable decoration");
}
TEST_F(ParserImplTest, VariableStorageDecoration_MissingLessThan) {
ParserImpl p{"in>"};
auto sc = p.variable_storage_decoration();
auto p = parser("in>");
auto sc = p->variable_storage_decoration();
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());
}
TEST_F(ParserImplTest, VariableStorageDecoration_MissingGreaterThan) {
ParserImpl p{"<in"};
auto sc = p.variable_storage_decoration();
auto p = parser("<in");
auto sc = p->variable_storage_decoration();
ASSERT_EQ(sc, ast::StorageClass::kNone);
ASSERT_TRUE(p.has_error());
ASSERT_EQ(p.error(), "1:4: missing > for variable decoration");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:4: missing > for variable decoration");
}
} // namespace wgsl

View File

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

View File

@ -17,25 +17,6 @@
#include <utility>
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;

View File

@ -24,16 +24,10 @@
namespace tint {
/// 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 {
public:
/// @returns a pointer to the type manager
static TypeManager* Instance();
/// Frees the type manager and any associated types. The types should not be
/// used after the manager is freed.
static void Destroy();
TypeManager();
~TypeManager();
/// Get the given type from the type manager
/// @param type The type to register
@ -41,9 +35,6 @@ class TypeManager {
ast::type::Type* Get(std::unique_ptr<ast::type::Type> type);
private:
TypeManager();
~TypeManager();
std::unordered_map<std::string, std::unique_ptr<ast::type::Type>> types_;
};

View File

@ -22,60 +22,33 @@ namespace tint {
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) {
auto tm = TypeManager::Instance();
auto t = tm->Get(std::make_unique<ast::type::I32Type>());
TypeManager tm;
auto t = tm.Get(std::make_unique<ast::type::I32Type>());
ASSERT_NE(t, nullptr);
EXPECT_TRUE(t->IsI32());
TypeManager::Destroy();
}
TEST_F(TypeManagerTest, GetSameTypeReturnsSamePtr) {
auto tm = TypeManager::Instance();
auto t = tm->Get(std::make_unique<ast::type::I32Type>());
TypeManager tm;
auto t = tm.Get(std::make_unique<ast::type::I32Type>());
ASSERT_NE(t, nullptr);
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);
TypeManager::Destroy();
}
TEST_F(TypeManagerTest, GetDifferentTypeReturnsDifferentPtr) {
auto tm = TypeManager::Instance();
auto t = tm->Get(std::make_unique<ast::type::I32Type>());
TypeManager tm;
auto t = tm.Get(std::make_unique<ast::type::I32Type>());
ASSERT_NE(t, nullptr);
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);
EXPECT_NE(t, t2);
EXPECT_TRUE(t2->IsU32());
TypeManager::Destroy();
}
} // namespace tint