Add `mat_prefix`, `vec_prefix`, `callable` and `type_decl_without_ident`
This CL adds the `mat_prefix`, `vec_prefix`, `callable` and `type_decl_without_ident` constructuctions. Bug: tint:1633 Change-Id: Id1fb0417f522b7da2ac6bd4441d17b0a35ae5f14 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/99880 Commit-Queue: Dan Sinclair <dsinclair@chromium.org> Reviewed-by: Ben Clayton <bclayton@google.com> Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
a34b10db38
commit
393de082d3
|
@ -1357,6 +1357,7 @@ if (tint_build_unittests) {
|
|||
"reader/wgsl/parser_impl_break_stmt_test.cc",
|
||||
"reader/wgsl/parser_impl_bug_cases_test.cc",
|
||||
"reader/wgsl/parser_impl_call_stmt_test.cc",
|
||||
"reader/wgsl/parser_impl_callable_test.cc",
|
||||
"reader/wgsl/parser_impl_case_body_test.cc",
|
||||
"reader/wgsl/parser_impl_compound_stmt_test.cc",
|
||||
"reader/wgsl/parser_impl_const_literal_test.cc",
|
||||
|
@ -1418,6 +1419,7 @@ if (tint_build_unittests) {
|
|||
"reader/wgsl/parser_impl_texture_sampler_test.cc",
|
||||
"reader/wgsl/parser_impl_type_alias_test.cc",
|
||||
"reader/wgsl/parser_impl_type_decl_test.cc",
|
||||
"reader/wgsl/parser_impl_type_decl_without_ident_test.cc",
|
||||
"reader/wgsl/parser_impl_unary_expression_test.cc",
|
||||
"reader/wgsl/parser_impl_variable_attribute_list_test.cc",
|
||||
"reader/wgsl/parser_impl_variable_attribute_test.cc",
|
||||
|
@ -1425,6 +1427,7 @@ if (tint_build_unittests) {
|
|||
"reader/wgsl/parser_impl_variable_ident_decl_test.cc",
|
||||
"reader/wgsl/parser_impl_variable_qualifier_test.cc",
|
||||
"reader/wgsl/parser_impl_variable_stmt_test.cc",
|
||||
"reader/wgsl/parser_impl_vec_mat_prefix_test.cc",
|
||||
"reader/wgsl/parser_impl_while_stmt_test.cc",
|
||||
"reader/wgsl/parser_test.cc",
|
||||
"reader/wgsl/token_test.cc",
|
||||
|
|
|
@ -952,6 +952,7 @@ if(TINT_BUILD_TESTS)
|
|||
reader/wgsl/parser_impl_break_stmt_test.cc
|
||||
reader/wgsl/parser_impl_bug_cases_test.cc
|
||||
reader/wgsl/parser_impl_call_stmt_test.cc
|
||||
reader/wgsl/parser_impl_callable_test.cc
|
||||
reader/wgsl/parser_impl_case_body_test.cc
|
||||
reader/wgsl/parser_impl_compound_stmt_test.cc
|
||||
reader/wgsl/parser_impl_const_literal_test.cc
|
||||
|
@ -1013,6 +1014,7 @@ if(TINT_BUILD_TESTS)
|
|||
reader/wgsl/parser_impl_texture_sampler_test.cc
|
||||
reader/wgsl/parser_impl_type_alias_test.cc
|
||||
reader/wgsl/parser_impl_type_decl_test.cc
|
||||
reader/wgsl/parser_impl_type_decl_without_ident_test.cc
|
||||
reader/wgsl/parser_impl_unary_expression_test.cc
|
||||
reader/wgsl/parser_impl_variable_decl_test.cc
|
||||
reader/wgsl/parser_impl_variable_attribute_list_test.cc
|
||||
|
@ -1020,6 +1022,7 @@ if(TINT_BUILD_TESTS)
|
|||
reader/wgsl/parser_impl_variable_ident_decl_test.cc
|
||||
reader/wgsl/parser_impl_variable_stmt_test.cc
|
||||
reader/wgsl/parser_impl_variable_qualifier_test.cc
|
||||
reader/wgsl/parser_impl_vec_mat_prefix_test.cc
|
||||
reader/wgsl/parser_impl_while_stmt_test.cc
|
||||
reader/wgsl/token_test.cc
|
||||
)
|
||||
|
|
|
@ -1059,6 +1059,132 @@ Maybe<const ast::Alias*> ParserImpl::type_alias_decl() {
|
|||
return builder_.ty.alias(make_source_range_from(t.source()), name.value, type.value);
|
||||
}
|
||||
|
||||
// vec_prefix
|
||||
// : 'vec2'
|
||||
// | 'vec3'
|
||||
// | 'vec4'
|
||||
Maybe<uint32_t> ParserImpl::vec_prefix() {
|
||||
auto& t = peek();
|
||||
if (!t.IsVector()) {
|
||||
return Failure::kNoMatch;
|
||||
}
|
||||
next();
|
||||
|
||||
if (t.Is(Token::Type::kVec3)) {
|
||||
return 3u;
|
||||
}
|
||||
if (t.Is(Token::Type::kVec4)) {
|
||||
return 4u;
|
||||
}
|
||||
return 2u;
|
||||
}
|
||||
|
||||
// mat_prefix
|
||||
// : 'mat2x2'
|
||||
// | 'mat2x3'
|
||||
// | 'mat2x4'
|
||||
// | 'mat3x2'
|
||||
// | 'mat3x3'
|
||||
// | 'mat3x4'
|
||||
// | 'mat4x2'
|
||||
// | 'mat4x3'
|
||||
// | 'mat4x4'
|
||||
Maybe<ParserImpl::MatrixDimensions> ParserImpl::mat_prefix() {
|
||||
auto& t = peek();
|
||||
if (!t.IsMatrix()) {
|
||||
return Failure::kNoMatch;
|
||||
}
|
||||
next();
|
||||
|
||||
uint32_t columns = 2;
|
||||
if (t.IsMat3xN()) {
|
||||
columns = 3;
|
||||
} else if (t.IsMat4xN()) {
|
||||
columns = 4;
|
||||
}
|
||||
if (t.IsMatNx3()) {
|
||||
return MatrixDimensions{columns, 3};
|
||||
}
|
||||
if (t.IsMatNx4()) {
|
||||
return MatrixDimensions{columns, 4};
|
||||
}
|
||||
return MatrixDimensions{columns, 2};
|
||||
}
|
||||
|
||||
// type_decl_without_ident:
|
||||
// : BOOL
|
||||
// | F16
|
||||
// | F32
|
||||
// | I32
|
||||
// | U32
|
||||
// | ARRAY LESS_THAN type_decl ( COMMA element_count_expression )? GREATER_THAN
|
||||
// | ATOMIC LESS_THAN type_decl GREATER_THAN
|
||||
// | PTR LESS_THAN address_space COMMA type_decl ( COMMA access_mode )? GREATER_THAN
|
||||
// | mat_prefix LESS_THAN type_decl GREATER_THAN
|
||||
// | vec_prefix LESS_THAN type_decl GREATER_THAN
|
||||
// | texture_and_sampler_types
|
||||
Maybe<const ast::Type*> ParserImpl::type_decl_without_ident() {
|
||||
auto& t = peek();
|
||||
|
||||
if (match(Token::Type::kBool)) {
|
||||
return builder_.ty.bool_(t.source());
|
||||
}
|
||||
|
||||
if (match(Token::Type::kF16)) {
|
||||
return builder_.ty.f16(t.source());
|
||||
}
|
||||
|
||||
if (match(Token::Type::kF32)) {
|
||||
return builder_.ty.f32(t.source());
|
||||
}
|
||||
|
||||
if (match(Token::Type::kI32)) {
|
||||
return builder_.ty.i32(t.source());
|
||||
}
|
||||
|
||||
if (match(Token::Type::kU32)) {
|
||||
return builder_.ty.u32(t.source());
|
||||
}
|
||||
|
||||
if (t.Is(Token::Type::kArray) && peek_is(Token::Type::kLessThan, 1)) {
|
||||
if (match(Token::Type::kArray)) {
|
||||
return expect_type_decl_array(t.source());
|
||||
}
|
||||
}
|
||||
|
||||
if (match(Token::Type::kAtomic)) {
|
||||
return expect_type_decl_atomic(t.source());
|
||||
}
|
||||
|
||||
if (match(Token::Type::kPtr)) {
|
||||
return expect_type_decl_pointer(t.source());
|
||||
}
|
||||
|
||||
if (t.IsMatrix() && peek_is(Token::Type::kLessThan, 1)) {
|
||||
auto mat = mat_prefix();
|
||||
if (mat.matched) {
|
||||
return expect_type_decl_matrix(t.source(), mat.value);
|
||||
}
|
||||
}
|
||||
|
||||
if (t.IsVector() && peek_is(Token::Type::kLessThan, 1)) {
|
||||
auto vec = vec_prefix();
|
||||
if (vec.matched) {
|
||||
return expect_type_decl_vector(t.source(), vec.value);
|
||||
}
|
||||
}
|
||||
|
||||
auto texture_or_sampler = texture_and_sampler_types();
|
||||
if (texture_or_sampler.errored) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
if (texture_or_sampler.matched) {
|
||||
return texture_or_sampler;
|
||||
}
|
||||
|
||||
return Failure::kNoMatch;
|
||||
}
|
||||
|
||||
// type_decl
|
||||
// : IDENTIFIER
|
||||
// | BOOL
|
||||
|
@ -1152,6 +1278,47 @@ Expect<const ast::Type*> ParserImpl::expect_type(std::string_view use) {
|
|||
return type.value;
|
||||
}
|
||||
|
||||
// LESS_THAN address_space COMMA type_decl ( COMMA access_mode )? GREATER_THAN
|
||||
Expect<const ast::Type*> ParserImpl::expect_type_decl_pointer(const Source& s) {
|
||||
const char* use = "ptr declaration";
|
||||
|
||||
auto storage_class = ast::StorageClass::kNone;
|
||||
auto access = ast::Access::kUndefined;
|
||||
|
||||
auto subtype = expect_lt_gt_block(use, [&]() -> Expect<const ast::Type*> {
|
||||
auto sc = expect_address_space(use);
|
||||
if (sc.errored) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
storage_class = sc.value;
|
||||
|
||||
if (!expect(use, Token::Type::kComma)) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
|
||||
auto type = expect_type(use);
|
||||
if (type.errored) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
|
||||
if (match(Token::Type::kComma)) {
|
||||
auto ac = expect_access_mode("access control");
|
||||
if (ac.errored) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
access = ac.value;
|
||||
}
|
||||
|
||||
return type.value;
|
||||
});
|
||||
|
||||
if (subtype.errored) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
|
||||
return builder_.ty.pointer(make_source_range_from(s), subtype.value, storage_class, access);
|
||||
}
|
||||
|
||||
Expect<const ast::Type*> ParserImpl::expect_type_decl_pointer(const Token& t) {
|
||||
const char* use = "ptr declaration";
|
||||
|
||||
|
@ -1193,6 +1360,18 @@ Expect<const ast::Type*> ParserImpl::expect_type_decl_pointer(const Token& t) {
|
|||
access);
|
||||
}
|
||||
|
||||
// LESS_THAN type_decl GREATER_THAN
|
||||
Expect<const ast::Type*> ParserImpl::expect_type_decl_atomic(const Source& s) {
|
||||
const char* use = "atomic declaration";
|
||||
|
||||
auto subtype = expect_lt_gt_block(use, [&] { return expect_type(use); });
|
||||
if (subtype.errored) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
|
||||
return builder_.ty.atomic(make_source_range_from(s), subtype.value);
|
||||
}
|
||||
|
||||
Expect<const ast::Type*> ParserImpl::expect_type_decl_atomic(const Token& t) {
|
||||
const char* use = "atomic declaration";
|
||||
|
||||
|
@ -1204,6 +1383,17 @@ Expect<const ast::Type*> ParserImpl::expect_type_decl_atomic(const Token& t) {
|
|||
return builder_.ty.atomic(make_source_range_from(t.source()), subtype.value);
|
||||
}
|
||||
|
||||
// LESS_THAN type_decl GREATER_THAN
|
||||
Expect<const ast::Type*> ParserImpl::expect_type_decl_vector(const Source& s, uint32_t count) {
|
||||
const char* use = "vector";
|
||||
auto ty = expect_lt_gt_block(use, [&] { return expect_type(use); });
|
||||
if (ty.errored) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
|
||||
return builder_.ty.vec(make_source_range_from(s), ty.value, count);
|
||||
}
|
||||
|
||||
Expect<const ast::Type*> ParserImpl::expect_type_decl_vector(const Token& t) {
|
||||
uint32_t count = 2;
|
||||
if (t.Is(Token::Type::kVec3)) {
|
||||
|
@ -1225,6 +1415,47 @@ Expect<const ast::Type*> ParserImpl::expect_type_decl_vector(const Token& t) {
|
|||
return builder_.ty.vec(make_source_range_from(t.source()), subtype, count);
|
||||
}
|
||||
|
||||
// LESS_THAN type_decl ( COMMA element_count_expression )? GREATER_THAN
|
||||
Expect<const ast::Type*> ParserImpl::expect_type_decl_array(const Source& s) {
|
||||
const char* use = "array declaration";
|
||||
|
||||
struct TypeAndSize {
|
||||
const ast::Type* type = nullptr;
|
||||
const ast::Expression* size = nullptr;
|
||||
};
|
||||
|
||||
if (!peek_is(Token::Type::kLessThan)) {
|
||||
return add_error(peek(), "expected < for array");
|
||||
}
|
||||
|
||||
auto type_size = expect_lt_gt_block(use, [&]() -> Expect<TypeAndSize> {
|
||||
auto type = expect_type(use);
|
||||
if (type.errored) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
|
||||
if (!match(Token::Type::kComma)) {
|
||||
return TypeAndSize{type.value, nullptr};
|
||||
}
|
||||
|
||||
auto size = element_count_expression();
|
||||
if (size.errored) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
if (!size.matched) {
|
||||
return add_error(peek(), "expected array size expression");
|
||||
}
|
||||
|
||||
return TypeAndSize{type.value, size.value};
|
||||
});
|
||||
|
||||
if (type_size.errored) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
|
||||
return builder_.ty.array(make_source_range_from(s), type_size->type, type_size->size);
|
||||
}
|
||||
|
||||
Expect<const ast::Type*> ParserImpl::expect_type_decl_array(const Token& t) {
|
||||
const char* use = "array declaration";
|
||||
|
||||
|
@ -1265,6 +1496,18 @@ Expect<const ast::Type*> ParserImpl::expect_type_decl_array(const Token& t) {
|
|||
return builder_.ty.array(make_source_range_from(t.source()), type_size->type, type_size->size);
|
||||
}
|
||||
|
||||
// LESS_THAN type_decl GREATER_THAN
|
||||
Expect<const ast::Type*> ParserImpl::expect_type_decl_matrix(const Source& s,
|
||||
const MatrixDimensions& dims) {
|
||||
const char* use = "matrix";
|
||||
auto ty = expect_lt_gt_block(use, [&] { return expect_type(use); });
|
||||
if (ty.errored) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
|
||||
return builder_.ty.mat(make_source_range_from(s), ty.value, dims.columns, dims.rows);
|
||||
}
|
||||
|
||||
Expect<const ast::Type*> ParserImpl::expect_type_decl_matrix(const Token& t) {
|
||||
uint32_t rows = 2;
|
||||
uint32_t columns = 2;
|
||||
|
@ -2438,6 +2681,47 @@ Maybe<const ast::BlockStatement*> ParserImpl::continuing_statement() {
|
|||
return continuing_compound_statement();
|
||||
}
|
||||
|
||||
// callable
|
||||
// : type_decl_without_ident
|
||||
// | ARRAY
|
||||
// | mat_prefix
|
||||
// | vec_prefix
|
||||
//
|
||||
// Note, `ident` is pulled out to `primary_expression` as it's the only one that
|
||||
// doesn't create a `type`. Then we can just return a `type` from here on match and
|
||||
// deal with `ident` in `primary_expression.
|
||||
Maybe<const ast::Type*> ParserImpl::callable() {
|
||||
auto& t = peek();
|
||||
|
||||
// This _must_ match `type_decl_without_ident` before any of the other types as they're all
|
||||
// prefixes of the types and we want to match the longer `vec3<f32>` then the shorter
|
||||
// prefix match of `vec3`.
|
||||
auto ty = type_decl_without_ident();
|
||||
if (ty.errored) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
if (ty.matched) {
|
||||
return ty.value;
|
||||
}
|
||||
|
||||
if (match(Token::Type::kArray)) {
|
||||
return builder_.ty.array(make_source_range_from(t.source()), nullptr, nullptr);
|
||||
}
|
||||
|
||||
auto vec = vec_prefix();
|
||||
if (vec.matched) {
|
||||
return builder_.ty.vec(make_source_range_from(t.source()), nullptr, vec.value);
|
||||
}
|
||||
|
||||
auto mat = mat_prefix();
|
||||
if (mat.matched) {
|
||||
return builder_.ty.mat(make_source_range_from(t.source()), nullptr, mat.value.columns,
|
||||
mat.value.rows);
|
||||
}
|
||||
|
||||
return Failure::kNoMatch;
|
||||
}
|
||||
|
||||
// primary_expression
|
||||
// : IDENT argument_expression_list?
|
||||
// | type_decl argument_expression_list
|
||||
|
|
|
@ -309,6 +309,14 @@ class ParserImpl {
|
|||
ast::Access access = ast::Access::kUndefined;
|
||||
};
|
||||
|
||||
/// MatrixDimensions contains the column and row information for a matrix
|
||||
struct MatrixDimensions {
|
||||
/// The number of columns
|
||||
uint32_t columns = 0;
|
||||
/// The number of rows
|
||||
uint32_t rows = 0;
|
||||
};
|
||||
|
||||
/// Creates a new parser using the given file
|
||||
/// @param file the input source file to parse
|
||||
explicit ParserImpl(Source::File const* file);
|
||||
|
@ -435,6 +443,18 @@ class ParserImpl {
|
|||
/// Parses a `type_alias_decl` grammar element
|
||||
/// @returns the type alias or nullptr on error
|
||||
Maybe<const ast::Alias*> type_alias_decl();
|
||||
/// Parses a `callable` grammar element
|
||||
/// @returns the type or nullptr
|
||||
Maybe<const ast::Type*> callable();
|
||||
/// Parses a `vec_prefix` grammar element
|
||||
/// @returns the vector size or nullptr
|
||||
Maybe<uint32_t> vec_prefix();
|
||||
/// Parses a `mat_prefix` grammar element
|
||||
/// @returns the matrix dimensions or nullptr
|
||||
Maybe<MatrixDimensions> mat_prefix();
|
||||
/// Parses a `type_decl_without_ident` grammar element
|
||||
/// @returns the parsed Type or nullptr if none matched.
|
||||
Maybe<const ast::Type*> type_decl_without_ident();
|
||||
/// Parses a `type_decl` grammar element
|
||||
/// @returns the parsed Type or nullptr if none matched.
|
||||
Maybe<const ast::Type*> type_decl();
|
||||
|
@ -919,12 +939,17 @@ class ParserImpl {
|
|||
/// Used to ensure that all attributes are consumed.
|
||||
bool expect_attributes_consumed(utils::VectorRef<const ast::Attribute*> list);
|
||||
|
||||
Expect<const ast::Type*> expect_type_decl_pointer(const Source& s);
|
||||
Expect<const ast::Type*> expect_type_decl_atomic(const Source& s);
|
||||
Expect<const ast::Type*> expect_type_decl_vector(const Source& s, uint32_t count);
|
||||
Expect<const ast::Type*> expect_type_decl_array(const Source& s);
|
||||
Expect<const ast::Type*> expect_type_decl_matrix(const Source& s, const MatrixDimensions& dims);
|
||||
|
||||
Expect<const ast::Type*> expect_type_decl_pointer(const Token& t);
|
||||
Expect<const ast::Type*> expect_type_decl_atomic(const Token& t);
|
||||
Expect<const ast::Type*> expect_type_decl_vector(const Token& t);
|
||||
Expect<const ast::Type*> expect_type_decl_array(const Token& t);
|
||||
Expect<const ast::Type*> expect_type_decl_matrix(const Token& t);
|
||||
|
||||
Expect<const ast::Type*> expect_type(std::string_view use);
|
||||
|
||||
Maybe<const ast::Statement*> non_block_statement();
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
// 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.
|
||||
|
||||
#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
|
||||
|
||||
namespace tint::reader::wgsl {
|
||||
namespace {
|
||||
|
||||
TEST_F(ParserImplTest, Callable_Array) {
|
||||
auto p = parser("array");
|
||||
auto t = p->callable();
|
||||
ASSERT_TRUE(p->peek_is(Token::Type::kEOF));
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
ASSERT_NE(t.value, nullptr);
|
||||
ASSERT_TRUE(t.value->Is<ast::Array>());
|
||||
|
||||
auto* a = t.value->As<ast::Array>();
|
||||
EXPECT_FALSE(a->IsRuntimeArray());
|
||||
EXPECT_EQ(a->type, nullptr);
|
||||
EXPECT_EQ(a->count, nullptr);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, Callable_VecPrefix) {
|
||||
auto p = parser("vec3");
|
||||
auto t = p->callable();
|
||||
ASSERT_TRUE(p->peek_is(Token::Type::kEOF));
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
ASSERT_NE(t.value, nullptr);
|
||||
ASSERT_TRUE(t.value->Is<ast::Vector>());
|
||||
|
||||
auto* v = t.value->As<ast::Vector>();
|
||||
EXPECT_EQ(v->type, nullptr);
|
||||
EXPECT_EQ(v->width, 3u);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, Callable_MatPrefix) {
|
||||
auto p = parser("mat3x2");
|
||||
auto t = p->callable();
|
||||
ASSERT_TRUE(p->peek_is(Token::Type::kEOF));
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
ASSERT_NE(t.value, nullptr);
|
||||
ASSERT_TRUE(t.value->Is<ast::Matrix>());
|
||||
|
||||
auto* m = t.value->As<ast::Matrix>();
|
||||
EXPECT_EQ(m->type, nullptr);
|
||||
EXPECT_EQ(m->columns, 3u);
|
||||
EXPECT_EQ(m->rows, 2u);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, Callable_TypeDecl_F32) {
|
||||
auto p = parser("f32");
|
||||
auto t = p->callable();
|
||||
ASSERT_TRUE(p->peek_is(Token::Type::kEOF));
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
ASSERT_NE(t.value, nullptr);
|
||||
ASSERT_TRUE(t.value->Is<ast::F32>());
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, Callable_TypeDecl_Array) {
|
||||
auto p = parser("array<f32, 2>");
|
||||
auto t = p->callable();
|
||||
ASSERT_TRUE(p->peek_is(Token::Type::kEOF));
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
ASSERT_NE(t.value, nullptr);
|
||||
ASSERT_TRUE(t.value->Is<ast::Array>());
|
||||
|
||||
auto* a = t.value->As<ast::Array>();
|
||||
EXPECT_FALSE(a->IsRuntimeArray());
|
||||
EXPECT_TRUE(a->type->Is<ast::F32>());
|
||||
|
||||
auto* size = a->count->As<ast::IntLiteralExpression>();
|
||||
ASSERT_NE(size, nullptr);
|
||||
EXPECT_EQ(size->value, 2);
|
||||
EXPECT_EQ(size->suffix, ast::IntLiteralExpression::Suffix::kNone);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, Callable_TypeDecl_Array_Runtime) {
|
||||
auto p = parser("array<f32>");
|
||||
auto t = p->callable();
|
||||
ASSERT_TRUE(p->peek_is(Token::Type::kEOF));
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
ASSERT_NE(t.value, nullptr);
|
||||
ASSERT_TRUE(t.value->Is<ast::Array>());
|
||||
|
||||
auto* a = t.value->As<ast::Array>();
|
||||
EXPECT_TRUE(a->IsRuntimeArray());
|
||||
EXPECT_TRUE(a->type->Is<ast::F32>());
|
||||
|
||||
ASSERT_EQ(a->count, nullptr);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, Callable_TypeDecl_VecPrefix) {
|
||||
auto p = parser("vec3<f32>");
|
||||
auto t = p->callable();
|
||||
ASSERT_TRUE(p->peek_is(Token::Type::kEOF));
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
ASSERT_NE(t.value, nullptr);
|
||||
ASSERT_TRUE(t.value->Is<ast::Vector>());
|
||||
|
||||
auto* v = t.value->As<ast::Vector>();
|
||||
EXPECT_TRUE(v->type->Is<ast::F32>());
|
||||
EXPECT_EQ(v->width, 3u);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, Callable_TypeDecl_MatPrefix) {
|
||||
auto p = parser("mat3x2<f32>");
|
||||
auto t = p->callable();
|
||||
ASSERT_TRUE(p->peek_is(Token::Type::kEOF));
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
ASSERT_NE(t.value, nullptr);
|
||||
ASSERT_TRUE(t.value->Is<ast::Matrix>());
|
||||
|
||||
auto* m = t.value->As<ast::Matrix>();
|
||||
EXPECT_TRUE(m->type->Is<ast::F32>());
|
||||
EXPECT_EQ(m->columns, 3u);
|
||||
EXPECT_EQ(m->rows, 2u);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, Callable_NoMatch) {
|
||||
auto p = parser("ident");
|
||||
auto t = p->callable();
|
||||
EXPECT_FALSE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
EXPECT_EQ(nullptr, t.value);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace tint::reader::wgsl
|
|
@ -0,0 +1,676 @@
|
|||
// 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.
|
||||
|
||||
#include "src/tint/ast/alias.h"
|
||||
#include "src/tint/ast/array.h"
|
||||
#include "src/tint/ast/matrix.h"
|
||||
#include "src/tint/ast/sampler.h"
|
||||
#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
|
||||
#include "src/tint/sem/sampled_texture.h"
|
||||
|
||||
namespace tint::reader::wgsl {
|
||||
namespace {
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Invalid) {
|
||||
auto p = parser("1234");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_EQ(t.errored, false);
|
||||
EXPECT_EQ(t.matched, false);
|
||||
EXPECT_EQ(t.value, nullptr);
|
||||
EXPECT_FALSE(p->has_error()) << p->error();
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Identifier) {
|
||||
auto p = parser("A");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_FALSE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
EXPECT_FALSE(p->has_error()) << p->error();
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Bool) {
|
||||
auto p = parser("bool");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_TRUE(t.value->Is<ast::Bool>());
|
||||
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 5u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_F16) {
|
||||
auto p = parser("f16");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_TRUE(t.value->Is<ast::F16>());
|
||||
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 4u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_F32) {
|
||||
auto p = parser("f32");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_TRUE(t.value->Is<ast::F32>());
|
||||
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 4u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_I32) {
|
||||
auto p = parser("i32");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_TRUE(t.value->Is<ast::I32>());
|
||||
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 4u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_U32) {
|
||||
auto p = parser("u32");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_TRUE(t.value->Is<ast::U32>());
|
||||
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 4u}}));
|
||||
}
|
||||
|
||||
struct VecData {
|
||||
const char* input;
|
||||
size_t count;
|
||||
Source::Range range;
|
||||
};
|
||||
inline std::ostream& operator<<(std::ostream& out, VecData data) {
|
||||
out << std::string(data.input);
|
||||
return out;
|
||||
}
|
||||
|
||||
class TypeDeclWithoutIdent_VecTest : public ParserImplTestWithParam<VecData> {};
|
||||
|
||||
TEST_P(TypeDeclWithoutIdent_VecTest, Parse) {
|
||||
auto params = GetParam();
|
||||
auto p = parser(params.input);
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_FALSE(p->has_error());
|
||||
EXPECT_TRUE(t.value->Is<ast::Vector>());
|
||||
EXPECT_EQ(t.value->As<ast::Vector>()->width, params.count);
|
||||
EXPECT_EQ(t.value->source.range, params.range);
|
||||
}
|
||||
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
|
||||
TypeDeclWithoutIdent_VecTest,
|
||||
testing::Values(VecData{"vec2<f32>", 2, {{1u, 1u}, {1u, 10u}}},
|
||||
VecData{"vec3<f32>", 3, {{1u, 1u}, {1u, 10u}}},
|
||||
VecData{"vec4<f32>", 4, {{1u, 1u}, {1u, 10u}}}));
|
||||
|
||||
class TypeDeclWithoutIdent_VecMissingGreaterThanTest : public ParserImplTestWithParam<VecData> {};
|
||||
|
||||
TEST_P(TypeDeclWithoutIdent_VecMissingGreaterThanTest, Handles_Missing_GreaterThan) {
|
||||
auto params = GetParam();
|
||||
auto p = parser(params.input);
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:9: expected '>' for vector");
|
||||
}
|
||||
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
|
||||
TypeDeclWithoutIdent_VecMissingGreaterThanTest,
|
||||
testing::Values(VecData{"vec2<f32", 2, {}},
|
||||
VecData{"vec3<f32", 3, {}},
|
||||
VecData{"vec4<f32", 4, {}}));
|
||||
|
||||
class TypeDeclWithoutIdent_VecMissingType : public ParserImplTestWithParam<VecData> {};
|
||||
|
||||
TEST_P(TypeDeclWithoutIdent_VecMissingType, Handles_Missing_Type) {
|
||||
auto params = GetParam();
|
||||
auto p = parser(params.input);
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:6: invalid type for vector");
|
||||
}
|
||||
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
|
||||
TypeDeclWithoutIdent_VecMissingType,
|
||||
testing::Values(VecData{"vec2<>", 2, {}},
|
||||
VecData{"vec3<>", 3, {}},
|
||||
VecData{"vec4<>", 4, {}}));
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr) {
|
||||
auto p = parser("ptr<function, f32>");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_FALSE(p->has_error());
|
||||
ASSERT_TRUE(t.value->Is<ast::Pointer>());
|
||||
|
||||
auto* ptr = t.value->As<ast::Pointer>();
|
||||
ASSERT_TRUE(ptr->type->Is<ast::F32>());
|
||||
ASSERT_EQ(ptr->storage_class, ast::StorageClass::kFunction);
|
||||
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 19u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_WithAccess) {
|
||||
auto p = parser("ptr<function, f32, read>");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_FALSE(p->has_error());
|
||||
ASSERT_TRUE(t.value->Is<ast::Pointer>());
|
||||
|
||||
auto* ptr = t.value->As<ast::Pointer>();
|
||||
ASSERT_TRUE(ptr->type->Is<ast::F32>());
|
||||
ASSERT_EQ(ptr->storage_class, ast::StorageClass::kFunction);
|
||||
ASSERT_EQ(ptr->access, ast::Access::kRead);
|
||||
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 25u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_ToVec) {
|
||||
auto p = parser("ptr<function, vec2<f32>>");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_FALSE(p->has_error());
|
||||
ASSERT_TRUE(t.value->Is<ast::Pointer>());
|
||||
|
||||
auto* ptr = t.value->As<ast::Pointer>();
|
||||
ASSERT_TRUE(ptr->type->Is<ast::Vector>());
|
||||
ASSERT_EQ(ptr->storage_class, ast::StorageClass::kFunction);
|
||||
|
||||
auto* vec = ptr->type->As<ast::Vector>();
|
||||
ASSERT_EQ(vec->width, 2u);
|
||||
ASSERT_TRUE(vec->type->Is<ast::F32>());
|
||||
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 25}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingLessThan) {
|
||||
auto p = parser("ptr private, f32>");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:5: expected '<' for ptr declaration");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingGreaterThanAfterType) {
|
||||
auto p = parser("ptr<function, f32");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:18: expected '>' for ptr declaration");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingGreaterThanAfterAccess) {
|
||||
auto p = parser("ptr<function, f32, read");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:24: expected '>' for ptr declaration");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingCommaAfterStorageClass) {
|
||||
auto p = parser("ptr<function f32>");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:14: expected ',' for ptr declaration");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingCommaAfterAccess) {
|
||||
auto p = parser("ptr<function, f32 read>");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:19: expected '>' for ptr declaration");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingStorageClass) {
|
||||
auto p = parser("ptr<, f32>");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:5: expected identifier for storage class");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingType) {
|
||||
auto p = parser("ptr<function,>");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:14: invalid type for ptr declaration");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingAccess) {
|
||||
auto p = parser("ptr<function, i32, >");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:20: expected identifier for access control");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_MissingParams) {
|
||||
auto p = parser("ptr<>");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:5: expected identifier for storage class");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_BadStorageClass) {
|
||||
auto p = parser("ptr<unknown, f32>");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:5: invalid storage class for ptr declaration");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Ptr_BadAccess) {
|
||||
auto p = parser("ptr<function, i32, unknown>");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:20: invalid value for access control");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Atomic) {
|
||||
auto p = parser("atomic<f32>");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_FALSE(p->has_error());
|
||||
ASSERT_TRUE(t.value->Is<ast::Atomic>());
|
||||
|
||||
auto* atomic = t.value->As<ast::Atomic>();
|
||||
ASSERT_TRUE(atomic->type->Is<ast::F32>());
|
||||
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 12u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Atomic_ToVec) {
|
||||
auto p = parser("atomic<vec2<f32>>");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_FALSE(p->has_error());
|
||||
ASSERT_TRUE(t.value->Is<ast::Atomic>());
|
||||
|
||||
auto* atomic = t.value->As<ast::Atomic>();
|
||||
ASSERT_TRUE(atomic->type->Is<ast::Vector>());
|
||||
|
||||
auto* vec = atomic->type->As<ast::Vector>();
|
||||
ASSERT_EQ(vec->width, 2u);
|
||||
ASSERT_TRUE(vec->type->Is<ast::F32>());
|
||||
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 18u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Atomic_MissingLessThan) {
|
||||
auto p = parser("atomic f32>");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:8: expected '<' for atomic declaration");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Atomic_MissingGreaterThan) {
|
||||
auto p = parser("atomic<f32");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:11: expected '>' for atomic declaration");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Atomic_MissingType) {
|
||||
auto p = parser("atomic<>");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:8: invalid type for atomic declaration");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Array_AbstractIntLiteralSize) {
|
||||
auto p = parser("array<f32, 5>");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_FALSE(p->has_error());
|
||||
ASSERT_TRUE(t.value->Is<ast::Array>());
|
||||
|
||||
auto* a = t.value->As<ast::Array>();
|
||||
ASSERT_FALSE(a->IsRuntimeArray());
|
||||
ASSERT_TRUE(a->type->Is<ast::F32>());
|
||||
EXPECT_EQ(a->attributes.Length(), 0u);
|
||||
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 14u}}));
|
||||
|
||||
auto* size = a->count->As<ast::IntLiteralExpression>();
|
||||
ASSERT_NE(size, nullptr);
|
||||
EXPECT_EQ(size->value, 5);
|
||||
EXPECT_EQ(size->suffix, ast::IntLiteralExpression::Suffix::kNone);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Array_SintLiteralSize) {
|
||||
auto p = parser("array<f32, 5i>");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_FALSE(p->has_error());
|
||||
ASSERT_TRUE(t.value->Is<ast::Array>());
|
||||
|
||||
auto* a = t.value->As<ast::Array>();
|
||||
ASSERT_FALSE(a->IsRuntimeArray());
|
||||
ASSERT_TRUE(a->type->Is<ast::F32>());
|
||||
EXPECT_EQ(a->attributes.Length(), 0u);
|
||||
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 15u}}));
|
||||
|
||||
auto* size = a->count->As<ast::IntLiteralExpression>();
|
||||
ASSERT_NE(size, nullptr);
|
||||
EXPECT_EQ(size->value, 5);
|
||||
EXPECT_EQ(size->suffix, ast::IntLiteralExpression::Suffix::kI);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Array_UintLiteralSize) {
|
||||
auto p = parser("array<f32, 5u>");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_FALSE(p->has_error());
|
||||
ASSERT_TRUE(t.value->Is<ast::Array>());
|
||||
|
||||
auto* a = t.value->As<ast::Array>();
|
||||
ASSERT_FALSE(a->IsRuntimeArray());
|
||||
ASSERT_TRUE(a->type->Is<ast::F32>());
|
||||
EXPECT_EQ(a->attributes.Length(), 0u);
|
||||
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 15u}}));
|
||||
|
||||
auto* size = a->count->As<ast::IntLiteralExpression>();
|
||||
ASSERT_NE(size, nullptr);
|
||||
EXPECT_EQ(size->suffix, ast::IntLiteralExpression::Suffix::kU);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Array_ConstantSize) {
|
||||
auto p = parser("array<f32, size>");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_FALSE(p->has_error());
|
||||
ASSERT_TRUE(t.value->Is<ast::Array>());
|
||||
|
||||
auto* a = t.value->As<ast::Array>();
|
||||
ASSERT_FALSE(a->IsRuntimeArray());
|
||||
ASSERT_TRUE(a->type->Is<ast::F32>());
|
||||
EXPECT_EQ(a->attributes.Length(), 0u);
|
||||
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 17u}}));
|
||||
|
||||
auto* count_expr = a->count->As<ast::IdentifierExpression>();
|
||||
ASSERT_NE(count_expr, nullptr);
|
||||
EXPECT_EQ(p->builder().Symbols().NameFor(count_expr->symbol), "size");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Array_ExpressionSize) {
|
||||
auto p = parser("array<f32, size + 2>");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_FALSE(p->has_error());
|
||||
ASSERT_TRUE(t.value->Is<ast::Array>());
|
||||
|
||||
auto* a = t.value->As<ast::Array>();
|
||||
ASSERT_FALSE(a->IsRuntimeArray());
|
||||
ASSERT_TRUE(a->type->Is<ast::F32>());
|
||||
EXPECT_EQ(a->attributes.Length(), 0u);
|
||||
|
||||
ASSERT_TRUE(a->count->Is<ast::BinaryExpression>());
|
||||
auto* count_expr = a->count->As<ast::BinaryExpression>();
|
||||
EXPECT_EQ(ast::BinaryOp::kAdd, count_expr->op);
|
||||
|
||||
ASSERT_TRUE(count_expr->lhs->Is<ast::IdentifierExpression>());
|
||||
auto* ident = count_expr->lhs->As<ast::IdentifierExpression>();
|
||||
EXPECT_EQ(p->builder().Symbols().NameFor(ident->symbol), "size");
|
||||
|
||||
ASSERT_TRUE(count_expr->rhs->Is<ast::IntLiteralExpression>());
|
||||
auto* val = count_expr->rhs->As<ast::IntLiteralExpression>();
|
||||
EXPECT_EQ(2, static_cast<int32_t>(val->value));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Array_Runtime) {
|
||||
auto p = parser("array<u32>");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_FALSE(p->has_error());
|
||||
ASSERT_TRUE(t.value->Is<ast::Array>());
|
||||
|
||||
auto* a = t.value->As<ast::Array>();
|
||||
ASSERT_TRUE(a->IsRuntimeArray());
|
||||
ASSERT_TRUE(a->type->Is<ast::U32>());
|
||||
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 11u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Array_Runtime_Vec) {
|
||||
auto p = parser("array<vec4<u32>>");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_FALSE(p->has_error());
|
||||
ASSERT_TRUE(t.value->Is<ast::Array>());
|
||||
|
||||
auto* a = t.value->As<ast::Array>();
|
||||
ASSERT_TRUE(a->IsRuntimeArray());
|
||||
ASSERT_TRUE(a->type->Is<ast::Vector>());
|
||||
EXPECT_EQ(a->type->As<ast::Vector>()->width, 4u);
|
||||
EXPECT_TRUE(a->type->As<ast::Vector>()->type->Is<ast::U32>());
|
||||
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 17u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Array_BadSize) {
|
||||
auto p = parser("array<f32, !>");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:13: unable to parse right side of ! expression");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Array_MissingSize) {
|
||||
auto p = parser("array<f32,>");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:11: expected array size expression");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Array_MissingGreaterThan) {
|
||||
auto p = parser("array<f32");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:10: expected '>' for array declaration");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Array_MissingComma) {
|
||||
auto p = parser("array<f32 3>");
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:11: expected '>' for array declaration");
|
||||
}
|
||||
|
||||
struct MatrixData {
|
||||
const char* input;
|
||||
size_t columns;
|
||||
size_t rows;
|
||||
Source::Range range;
|
||||
};
|
||||
inline std::ostream& operator<<(std::ostream& out, MatrixData data) {
|
||||
out << std::string(data.input);
|
||||
return out;
|
||||
}
|
||||
|
||||
class TypeDeclWithoutIdent_MatrixTest : public ParserImplTestWithParam<MatrixData> {};
|
||||
|
||||
TEST_P(TypeDeclWithoutIdent_MatrixTest, Parse) {
|
||||
auto params = GetParam();
|
||||
auto p = parser(params.input);
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_FALSE(p->has_error());
|
||||
EXPECT_TRUE(t.value->Is<ast::Matrix>());
|
||||
auto* mat = t.value->As<ast::Matrix>();
|
||||
EXPECT_EQ(mat->rows, params.rows);
|
||||
EXPECT_EQ(mat->columns, params.columns);
|
||||
EXPECT_EQ(t.value->source.range, params.range);
|
||||
}
|
||||
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
|
||||
TypeDeclWithoutIdent_MatrixTest,
|
||||
testing::Values(MatrixData{"mat2x2<f32>", 2, 2, {{1u, 1u}, {1u, 12u}}},
|
||||
MatrixData{"mat2x3<f32>", 2, 3, {{1u, 1u}, {1u, 12u}}},
|
||||
MatrixData{"mat2x4<f32>", 2, 4, {{1u, 1u}, {1u, 12u}}},
|
||||
MatrixData{"mat3x2<f32>", 3, 2, {{1u, 1u}, {1u, 12u}}},
|
||||
MatrixData{"mat3x3<f32>", 3, 3, {{1u, 1u}, {1u, 12u}}},
|
||||
MatrixData{"mat3x4<f32>", 3, 4, {{1u, 1u}, {1u, 12u}}},
|
||||
MatrixData{"mat4x2<f32>", 4, 2, {{1u, 1u}, {1u, 12u}}},
|
||||
MatrixData{"mat4x3<f32>", 4, 3, {{1u, 1u}, {1u, 12u}}},
|
||||
MatrixData{"mat4x4<f32>", 4, 4, {{1u, 1u}, {1u, 12u}}}));
|
||||
|
||||
class TypeDeclWithoutIdent_MatrixMissingGreaterThanTest
|
||||
: public ParserImplTestWithParam<MatrixData> {};
|
||||
|
||||
TEST_P(TypeDeclWithoutIdent_MatrixMissingGreaterThanTest, Handles_Missing_GreaterThan) {
|
||||
auto params = GetParam();
|
||||
auto p = parser(params.input);
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:11: expected '>' for matrix");
|
||||
}
|
||||
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
|
||||
TypeDeclWithoutIdent_MatrixMissingGreaterThanTest,
|
||||
testing::Values(MatrixData{"mat2x2<f32", 2, 2, {}},
|
||||
MatrixData{"mat2x3<f32", 2, 3, {}},
|
||||
MatrixData{"mat2x4<f32", 2, 4, {}},
|
||||
MatrixData{"mat3x2<f32", 3, 2, {}},
|
||||
MatrixData{"mat3x3<f32", 3, 3, {}},
|
||||
MatrixData{"mat3x4<f32", 3, 4, {}},
|
||||
MatrixData{"mat4x2<f32", 4, 2, {}},
|
||||
MatrixData{"mat4x3<f32", 4, 3, {}},
|
||||
MatrixData{"mat4x4<f32", 4, 4, {}}));
|
||||
|
||||
class TypeDeclWithoutIdent_MatrixMissingType : public ParserImplTestWithParam<MatrixData> {};
|
||||
|
||||
TEST_P(TypeDeclWithoutIdent_MatrixMissingType, Handles_Missing_Type) {
|
||||
auto params = GetParam();
|
||||
auto p = parser(params.input);
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:8: invalid type for matrix");
|
||||
}
|
||||
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
|
||||
TypeDeclWithoutIdent_MatrixMissingType,
|
||||
testing::Values(MatrixData{"mat2x2<>", 2, 2, {}},
|
||||
MatrixData{"mat2x3<>", 2, 3, {}},
|
||||
MatrixData{"mat2x4<>", 2, 4, {}},
|
||||
MatrixData{"mat3x2<>", 3, 2, {}},
|
||||
MatrixData{"mat3x3<>", 3, 3, {}},
|
||||
MatrixData{"mat3x4<>", 3, 4, {}},
|
||||
MatrixData{"mat4x2<>", 4, 2, {}},
|
||||
MatrixData{"mat4x3<>", 4, 3, {}},
|
||||
MatrixData{"mat4x4<>", 4, 4, {}}));
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Sampler) {
|
||||
auto p = parser("sampler");
|
||||
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_TRUE(t.value->Is<ast::Sampler>());
|
||||
ASSERT_FALSE(t.value->As<ast::Sampler>()->IsComparison());
|
||||
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 8u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDeclWithoutIdent_Texture) {
|
||||
auto p = parser("texture_cube<f32>");
|
||||
|
||||
auto t = p->type_decl_without_ident();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr);
|
||||
ASSERT_TRUE(t.value->Is<ast::Texture>());
|
||||
ASSERT_TRUE(t.value->Is<ast::SampledTexture>());
|
||||
ASSERT_TRUE(t.value->As<ast::SampledTexture>()->type->Is<ast::F32>());
|
||||
EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 18u}}));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace tint::reader::wgsl
|
|
@ -0,0 +1,103 @@
|
|||
// 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.
|
||||
|
||||
#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
|
||||
|
||||
namespace tint::reader::wgsl {
|
||||
namespace {
|
||||
|
||||
TEST_F(ParserImplTest, VecPrefix_Vec2) {
|
||||
auto p = parser("vec2");
|
||||
auto t = p->vec_prefix();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
|
||||
EXPECT_EQ(2u, t.value);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, VecPrefix_Vec3) {
|
||||
auto p = parser("vec3");
|
||||
auto t = p->vec_prefix();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
|
||||
EXPECT_EQ(3u, t.value);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, VecPrefix_Vec4) {
|
||||
auto p = parser("vec4");
|
||||
auto t = p->vec_prefix();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
|
||||
EXPECT_EQ(4u, t.value);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, VecPrefix_NoMatch) {
|
||||
auto p = parser("mat2x2");
|
||||
auto t = p->vec_prefix();
|
||||
EXPECT_FALSE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
|
||||
EXPECT_EQ(0u, t.value);
|
||||
}
|
||||
|
||||
struct MatData {
|
||||
std::string name;
|
||||
uint32_t columns;
|
||||
uint32_t rows;
|
||||
};
|
||||
class MatPrefixTest : public ParserImplTestWithParam<MatData> {};
|
||||
TEST_P(MatPrefixTest, Parse) {
|
||||
auto params = GetParam();
|
||||
|
||||
auto p = parser(params.name);
|
||||
auto t = p->mat_prefix();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
|
||||
auto dims = t.value;
|
||||
EXPECT_EQ(params.columns, dims.columns);
|
||||
EXPECT_EQ(params.rows, dims.rows);
|
||||
}
|
||||
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
|
||||
MatPrefixTest,
|
||||
testing::Values(MatData{"mat2x2", 2, 2},
|
||||
MatData{"mat2x3", 2, 3},
|
||||
MatData{"mat2x4", 2, 4},
|
||||
MatData{"mat3x2", 3, 2},
|
||||
MatData{"mat3x3", 3, 3},
|
||||
MatData{"mat3x4", 3, 4},
|
||||
MatData{"mat4x2", 4, 2},
|
||||
MatData{"mat4x3", 4, 3},
|
||||
MatData{"mat4x4", 4, 4}));
|
||||
|
||||
TEST_F(ParserImplTest, MatPrefix_NoMatch) {
|
||||
auto p = parser("vec2");
|
||||
auto t = p->mat_prefix();
|
||||
EXPECT_FALSE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
|
||||
EXPECT_EQ(0u, t.value.columns);
|
||||
EXPECT_EQ(0u, t.value.rows);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace tint::reader::wgsl
|
Loading…
Reference in New Issue