wgsl parser: use new TypesBuilder factory functions, and set Source for ast::Type nodes
* ProgramBuilder: added a bunch of overloads that take Source * Added MultiTokenSource RAII helper to build source ranges for multi-token types * Added comparison operators to Source::Range and Source::Location to make it easier to write tests to compare Source ranges * Moved CombineSourceRange from resolver.cc to a static function in Source named Source::Combine() * Added Source tests for all ast type nodes returned by the wgsl parser Bug: tint:724 Change-Id: I6fb6211a3c42c14693df8746af6a30f5aa56f2af Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/48963 Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Antonio Maiorano <amaiorano@google.com> Reviewed-by: Ben Clayton <bclayton@google.com>
This commit is contained in:
parent
a810d71df5
commit
4b16a160d5
|
@ -28,6 +28,7 @@
|
|||
#include "src/ast/call_expression.h"
|
||||
#include "src/ast/case_statement.h"
|
||||
#include "src/ast/depth_texture.h"
|
||||
#include "src/ast/external_texture.h"
|
||||
#include "src/ast/f32.h"
|
||||
#include "src/ast/float_literal.h"
|
||||
#include "src/ast/i32.h"
|
||||
|
@ -62,6 +63,7 @@
|
|||
#include "src/sem/array_type.h"
|
||||
#include "src/sem/bool_type.h"
|
||||
#include "src/sem/depth_texture_type.h"
|
||||
#include "src/sem/external_texture_type.h"
|
||||
#include "src/sem/f32_type.h"
|
||||
#include "src/sem/i32_type.h"
|
||||
#include "src/sem/matrix_type.h"
|
||||
|
@ -352,26 +354,56 @@ class ProgramBuilder {
|
|||
return {builder->create<ast::Bool>(), builder->create<sem::Bool>()};
|
||||
}
|
||||
|
||||
/// @param source the Source of the node
|
||||
/// @returns a boolean type
|
||||
typ::Bool bool_(const Source& source) const {
|
||||
return {builder->create<ast::Bool>(source), builder->create<sem::Bool>()};
|
||||
}
|
||||
|
||||
/// @returns a f32 type
|
||||
typ::F32 f32() const {
|
||||
return {builder->create<ast::F32>(), builder->create<sem::F32>()};
|
||||
}
|
||||
|
||||
/// @param source the Source of the node
|
||||
/// @returns a f32 type
|
||||
typ::F32 f32(const Source& source) const {
|
||||
return {builder->create<ast::F32>(source), builder->create<sem::F32>()};
|
||||
}
|
||||
|
||||
/// @returns a i32 type
|
||||
typ::I32 i32() const {
|
||||
return {builder->create<ast::I32>(), builder->create<sem::I32>()};
|
||||
}
|
||||
|
||||
/// @param source the Source of the node
|
||||
/// @returns a i32 type
|
||||
typ::I32 i32(const Source& source) const {
|
||||
return {builder->create<ast::I32>(source), builder->create<sem::I32>()};
|
||||
}
|
||||
|
||||
/// @returns a u32 type
|
||||
typ::U32 u32() const {
|
||||
return {builder->create<ast::U32>(), builder->create<sem::U32>()};
|
||||
}
|
||||
|
||||
/// @param source the Source of the node
|
||||
/// @returns a u32 type
|
||||
typ::U32 u32(const Source& source) const {
|
||||
return {builder->create<ast::U32>(source), builder->create<sem::U32>()};
|
||||
}
|
||||
|
||||
/// @returns a void type
|
||||
typ::Void void_() const {
|
||||
return {builder->create<ast::Void>(), builder->create<sem::Void>()};
|
||||
}
|
||||
|
||||
/// @param source the Source of the node
|
||||
/// @returns a void type
|
||||
typ::Void void_(const Source& source) const {
|
||||
return {builder->create<ast::Void>(source), builder->create<sem::Void>()};
|
||||
}
|
||||
|
||||
/// @param type vector subtype
|
||||
/// @param n vector width in elements
|
||||
/// @return the tint AST type for a `n`-element vector of `type`.
|
||||
|
@ -380,6 +412,15 @@ class ProgramBuilder {
|
|||
builder->create<sem::Vector>(type, n)};
|
||||
}
|
||||
|
||||
/// @param source the Source of the node
|
||||
/// @param type vector subtype
|
||||
/// @param n vector width in elements
|
||||
/// @return the tint AST type for a `n`-element vector of `type`.
|
||||
typ::Vector vec(const Source& source, typ::Type type, uint32_t n) const {
|
||||
return {builder->create<ast::Vector>(source, type, n),
|
||||
builder->create<sem::Vector>(type, n)};
|
||||
}
|
||||
|
||||
/// @param type vector subtype
|
||||
/// @return the tint AST type for a 2-element vector of `type`.
|
||||
typ::Vector vec2(typ::Type type) const { return vec(type, 2u); }
|
||||
|
@ -426,6 +467,19 @@ class ProgramBuilder {
|
|||
builder->create<sem::Matrix>(type, rows, columns)};
|
||||
}
|
||||
|
||||
/// @param source the Source of the node
|
||||
/// @param type matrix subtype
|
||||
/// @param columns number of columns for the matrix
|
||||
/// @param rows number of rows for the matrix
|
||||
/// @return the tint AST type for a matrix of `type`
|
||||
typ::Matrix mat(const Source& source,
|
||||
typ::Type type,
|
||||
uint32_t columns,
|
||||
uint32_t rows) const {
|
||||
return {builder->create<ast::Matrix>(source, type, rows, columns),
|
||||
builder->create<sem::Matrix>(type, rows, columns)};
|
||||
}
|
||||
|
||||
/// @param type matrix subtype
|
||||
/// @return the tint AST type for a 2x3 matrix of `type`.
|
||||
typ::Matrix mat2x2(typ::Type type) const {
|
||||
|
@ -560,7 +614,21 @@ class ProgramBuilder {
|
|||
ast::DecorationList decos = {}) const {
|
||||
subtype = MaybeCreateTypename(subtype);
|
||||
return {builder->create<ast::Array>(subtype, n, decos),
|
||||
builder->create<sem::ArrayType>(subtype, n, decos)};
|
||||
builder->create<sem::ArrayType>(subtype, n, std::move(decos))};
|
||||
}
|
||||
|
||||
/// @param source the Source of the node
|
||||
/// @param subtype the array element type
|
||||
/// @param n the array size. 0 represents a runtime-array
|
||||
/// @param decos the optional decorations for the array
|
||||
/// @return the tint AST type for a array of size `n` of type `T`
|
||||
typ::Array array(const Source& source,
|
||||
typ::Type subtype,
|
||||
uint32_t n = 0,
|
||||
ast::DecorationList decos = {}) const {
|
||||
subtype = MaybeCreateTypename(subtype);
|
||||
return {builder->create<ast::Array>(source, subtype, n, decos),
|
||||
builder->create<sem::ArrayType>(subtype, n, std::move(decos))};
|
||||
}
|
||||
|
||||
/// @param subtype the array element type
|
||||
|
@ -600,6 +668,21 @@ class ProgramBuilder {
|
|||
};
|
||||
}
|
||||
|
||||
/// Creates an alias type
|
||||
/// @param source the Source of the node
|
||||
/// @param name the alias name
|
||||
/// @param type the alias type
|
||||
/// @returns the alias pointer
|
||||
template <typename NAME>
|
||||
typ::Alias alias(const Source& source, NAME&& name, typ::Type type) const {
|
||||
type = MaybeCreateTypename(type);
|
||||
auto sym = builder->Sym(std::forward<NAME>(name));
|
||||
return {
|
||||
builder->create<ast::Alias>(source, sym, type),
|
||||
builder->create<sem::Alias>(sym, type),
|
||||
};
|
||||
}
|
||||
|
||||
/// Creates an access control qualifier type
|
||||
/// @param access the access control
|
||||
/// @param type the inner type
|
||||
|
@ -611,6 +694,19 @@ class ProgramBuilder {
|
|||
builder->create<sem::AccessControl>(access, type)};
|
||||
}
|
||||
|
||||
/// Creates an access control qualifier type
|
||||
/// @param source the Source of the node
|
||||
/// @param access the access control
|
||||
/// @param type the inner type
|
||||
/// @returns the access control qualifier type
|
||||
typ::AccessControl access(const Source& source,
|
||||
ast::AccessControl::Access access,
|
||||
typ::Type type) const {
|
||||
type = MaybeCreateTypename(type);
|
||||
return {builder->create<ast::AccessControl>(source, access, type),
|
||||
builder->create<sem::AccessControl>(access, type)};
|
||||
}
|
||||
|
||||
/// @param type the type of the pointer
|
||||
/// @param storage_class the storage class of the pointer
|
||||
/// @return the pointer to `type` with the given ast::StorageClass
|
||||
|
@ -621,6 +717,18 @@ class ProgramBuilder {
|
|||
builder->create<sem::Pointer>(type, storage_class)};
|
||||
}
|
||||
|
||||
/// @param source the Source of the node
|
||||
/// @param type the type of the pointer
|
||||
/// @param storage_class the storage class of the pointer
|
||||
/// @return the pointer to `type` with the given ast::StorageClass
|
||||
typ::Pointer pointer(const Source& source,
|
||||
typ::Type type,
|
||||
ast::StorageClass storage_class) const {
|
||||
type = MaybeCreateTypename(type);
|
||||
return {builder->create<ast::Pointer>(source, type, storage_class),
|
||||
builder->create<sem::Pointer>(type, storage_class)};
|
||||
}
|
||||
|
||||
/// @param storage_class the storage class of the pointer
|
||||
/// @return the pointer to type `T` with the given ast::StorageClass.
|
||||
template <typename T>
|
||||
|
@ -641,6 +749,14 @@ class ProgramBuilder {
|
|||
builder->create<sem::Sampler>(kind)};
|
||||
}
|
||||
|
||||
/// @param source the Source of the node
|
||||
/// @param kind the kind of sampler
|
||||
/// @returns the sampler
|
||||
typ::Sampler sampler(const Source& source, ast::SamplerKind kind) const {
|
||||
return {builder->create<ast::Sampler>(source, kind),
|
||||
builder->create<sem::Sampler>(kind)};
|
||||
}
|
||||
|
||||
/// @param dims the dimensionality of the texture
|
||||
/// @returns the depth texture
|
||||
typ::DepthTexture depth_texture(ast::TextureDimension dims) const {
|
||||
|
@ -648,6 +764,15 @@ class ProgramBuilder {
|
|||
builder->create<sem::DepthTexture>(dims)};
|
||||
}
|
||||
|
||||
/// @param source the Source of the node
|
||||
/// @param dims the dimensionality of the texture
|
||||
/// @returns the depth texture
|
||||
typ::DepthTexture depth_texture(const Source& source,
|
||||
ast::TextureDimension dims) const {
|
||||
return {builder->create<ast::DepthTexture>(source, dims),
|
||||
builder->create<sem::DepthTexture>(dims)};
|
||||
}
|
||||
|
||||
/// @param dims the dimensionality of the texture
|
||||
/// @param subtype the texture subtype.
|
||||
/// @returns the sampled texture
|
||||
|
@ -657,6 +782,17 @@ class ProgramBuilder {
|
|||
builder->create<sem::SampledTexture>(dims, subtype)};
|
||||
}
|
||||
|
||||
/// @param source the Source of the node
|
||||
/// @param dims the dimensionality of the texture
|
||||
/// @param subtype the texture subtype.
|
||||
/// @returns the sampled texture
|
||||
typ::SampledTexture sampled_texture(const Source& source,
|
||||
ast::TextureDimension dims,
|
||||
typ::Type subtype) const {
|
||||
return {builder->create<ast::SampledTexture>(source, dims, subtype),
|
||||
builder->create<sem::SampledTexture>(dims, subtype)};
|
||||
}
|
||||
|
||||
/// @param dims the dimensionality of the texture
|
||||
/// @param subtype the texture subtype.
|
||||
/// @returns the multisampled texture
|
||||
|
@ -666,6 +802,17 @@ class ProgramBuilder {
|
|||
builder->create<sem::MultisampledTexture>(dims, subtype)};
|
||||
}
|
||||
|
||||
/// @param source the Source of the node
|
||||
/// @param dims the dimensionality of the texture
|
||||
/// @param subtype the texture subtype.
|
||||
/// @returns the multisampled texture
|
||||
typ::MultisampledTexture multisampled_texture(const Source& source,
|
||||
ast::TextureDimension dims,
|
||||
typ::Type subtype) const {
|
||||
return {builder->create<ast::MultisampledTexture>(source, dims, subtype),
|
||||
builder->create<sem::MultisampledTexture>(dims, subtype)};
|
||||
}
|
||||
|
||||
/// @param dims the dimensionality of the texture
|
||||
/// @param format the image format of the texture
|
||||
/// @returns the storage texture
|
||||
|
@ -678,6 +825,28 @@ class ProgramBuilder {
|
|||
builder->create<sem::StorageTexture>(dims, format, sem_subtype)};
|
||||
}
|
||||
|
||||
/// @param source the Source of the node
|
||||
/// @param dims the dimensionality of the texture
|
||||
/// @param format the image format of the texture
|
||||
/// @returns the storage texture
|
||||
typ::StorageTexture storage_texture(const Source& source,
|
||||
ast::TextureDimension dims,
|
||||
ast::ImageFormat format) const {
|
||||
auto* ast_subtype = ast::StorageTexture::SubtypeFor(format, *builder);
|
||||
auto* sem_subtype =
|
||||
sem::StorageTexture::SubtypeFor(format, builder->Types());
|
||||
return {builder->create<ast::StorageTexture>(source, dims, format,
|
||||
ast_subtype),
|
||||
builder->create<sem::StorageTexture>(dims, format, sem_subtype)};
|
||||
}
|
||||
|
||||
/// @param source the Source of the node
|
||||
/// @returns the external texture
|
||||
typ::ExternalTexture external_texture(const Source& source) const {
|
||||
return {builder->create<ast::ExternalTexture>(source),
|
||||
builder->create<sem::ExternalTexture>()};
|
||||
}
|
||||
|
||||
/// If ty is a ast::Struct or ast::Alias, the returned type is an
|
||||
/// ast::TypeName of the given type's name, otherwise type is returned.
|
||||
/// @param type the type
|
||||
|
|
|
@ -177,9 +177,38 @@ struct BlockCounters {
|
|||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
/// RAII helper that combines a Source on construction with the last token's
|
||||
/// source when implicitly converted to `Source`.
|
||||
class ParserImpl::MultiTokenSource {
|
||||
public:
|
||||
/// Constructor that starts with Source at the current peek position
|
||||
/// @param parser the parser
|
||||
explicit MultiTokenSource(ParserImpl* parser)
|
||||
: MultiTokenSource(parser, parser->peek().source().Begin()) {}
|
||||
|
||||
/// Constructor that starts with the input `start` Source
|
||||
/// @param parser the parser
|
||||
/// @param start the start source of the range
|
||||
MultiTokenSource(ParserImpl* parser, const Source& start)
|
||||
: parser_(parser), start_(start) {}
|
||||
|
||||
/// Implicit conversion to Source that returns the combined source from start
|
||||
/// to the current last token's source.
|
||||
operator Source() const {
|
||||
Source end = parser_->last_token().source().End();
|
||||
if (end < start_) {
|
||||
end = start_;
|
||||
}
|
||||
return Source::Combine(start_, end);
|
||||
}
|
||||
|
||||
private:
|
||||
ParserImpl* parser_;
|
||||
Source start_;
|
||||
};
|
||||
|
||||
ParserImpl::TypedIdentifier::TypedIdentifier() = default;
|
||||
|
||||
ParserImpl::TypedIdentifier::TypedIdentifier(const TypedIdentifier&) = default;
|
||||
|
@ -266,15 +295,16 @@ Token ParserImpl::next() {
|
|||
if (!token_queue_.empty()) {
|
||||
auto t = token_queue_.front();
|
||||
token_queue_.pop_front();
|
||||
return t;
|
||||
last_token_ = t;
|
||||
return last_token_;
|
||||
}
|
||||
return lexer_->next();
|
||||
last_token_ = lexer_->next();
|
||||
return last_token_;
|
||||
}
|
||||
|
||||
Token ParserImpl::peek(size_t idx) {
|
||||
while (token_queue_.size() < (idx + 1))
|
||||
token_queue_.push_back(lexer_->next());
|
||||
|
||||
return token_queue_[idx];
|
||||
}
|
||||
|
||||
|
@ -282,6 +312,10 @@ Token ParserImpl::peek() {
|
|||
return peek(0);
|
||||
}
|
||||
|
||||
Token ParserImpl::last_token() const {
|
||||
return last_token_;
|
||||
}
|
||||
|
||||
void ParserImpl::register_constructed(const std::string& name,
|
||||
sem::Type* type) {
|
||||
registered_constructs_[name] = type;
|
||||
|
@ -560,6 +594,8 @@ Maybe<typ::Type> ParserImpl::texture_sampler_types() {
|
|||
if (type.matched)
|
||||
return type.value;
|
||||
|
||||
auto source_range = make_source_range();
|
||||
|
||||
auto dim = sampled_texture_type();
|
||||
if (dim.matched) {
|
||||
const char* use = "sampled texture type";
|
||||
|
@ -568,9 +604,7 @@ Maybe<typ::Type> ParserImpl::texture_sampler_types() {
|
|||
if (subtype.errored)
|
||||
return Failure::kErrored;
|
||||
|
||||
return typ::Type{
|
||||
builder_.create<ast::SampledTexture>(dim.value, subtype.value),
|
||||
builder_.create<sem::SampledTexture>(dim.value, subtype.value)};
|
||||
return builder_.ty.sampled_texture(source_range, dim.value, subtype.value);
|
||||
}
|
||||
|
||||
auto ms_dim = multisampled_texture_type();
|
||||
|
@ -581,9 +615,8 @@ Maybe<typ::Type> ParserImpl::texture_sampler_types() {
|
|||
if (subtype.errored)
|
||||
return Failure::kErrored;
|
||||
|
||||
return typ::Type{
|
||||
builder_.create<ast::MultisampledTexture>(ms_dim.value, subtype.value),
|
||||
builder_.create<sem::MultisampledTexture>(ms_dim.value, subtype.value)};
|
||||
return builder_.ty.multisampled_texture(source_range, ms_dim.value,
|
||||
subtype.value);
|
||||
}
|
||||
|
||||
auto storage = storage_texture_type();
|
||||
|
@ -596,14 +629,8 @@ Maybe<typ::Type> ParserImpl::texture_sampler_types() {
|
|||
if (format.errored)
|
||||
return Failure::kErrored;
|
||||
|
||||
auto* subtype = ast::StorageTexture::SubtypeFor(format.value, builder_);
|
||||
auto* subtype_sem =
|
||||
sem::StorageTexture::SubtypeFor(format.value, builder_.Types());
|
||||
|
||||
return typ::Type{builder_.create<ast::StorageTexture>(
|
||||
storage.value, format.value, subtype),
|
||||
builder_.create<sem::StorageTexture>(
|
||||
storage.value, format.value, subtype_sem)};
|
||||
return builder_.ty.storage_texture(source_range, storage.value,
|
||||
format.value);
|
||||
}
|
||||
|
||||
return Failure::kNoMatch;
|
||||
|
@ -613,14 +640,12 @@ Maybe<typ::Type> ParserImpl::texture_sampler_types() {
|
|||
// : SAMPLER
|
||||
// | SAMPLER_COMPARISON
|
||||
Maybe<typ::Type> ParserImpl::sampler_type() {
|
||||
if (match(Token::Type::kSampler))
|
||||
return typ::Type{builder_.create<ast::Sampler>(ast::SamplerKind::kSampler),
|
||||
builder_.create<sem::Sampler>(ast::SamplerKind::kSampler)};
|
||||
Source source;
|
||||
if (match(Token::Type::kSampler, &source))
|
||||
return builder_.ty.sampler(source, ast::SamplerKind::kSampler);
|
||||
|
||||
if (match(Token::Type::kComparisonSampler))
|
||||
return typ::Type{
|
||||
builder_.create<ast::Sampler>(ast::SamplerKind::kComparisonSampler),
|
||||
builder_.create<sem::Sampler>(ast::SamplerKind::kComparisonSampler)};
|
||||
if (match(Token::Type::kComparisonSampler, &source))
|
||||
return builder_.ty.sampler(source, ast::SamplerKind::kComparisonSampler);
|
||||
|
||||
return Failure::kNoMatch;
|
||||
}
|
||||
|
@ -657,9 +682,9 @@ Maybe<ast::TextureDimension> ParserImpl::sampled_texture_type() {
|
|||
// external_texture_type
|
||||
// : TEXTURE_EXTERNAL
|
||||
Maybe<typ::Type> ParserImpl::external_texture_type() {
|
||||
if (match(Token::Type::kTextureExternal)) {
|
||||
return typ::Type{builder_.create<ast::ExternalTexture>(),
|
||||
builder_.create<sem::ExternalTexture>()};
|
||||
Source source;
|
||||
if (match(Token::Type::kTextureExternal, &source)) {
|
||||
return builder_.ty.external_texture(source);
|
||||
}
|
||||
|
||||
return Failure::kNoMatch;
|
||||
|
@ -698,25 +723,19 @@ Maybe<ast::TextureDimension> ParserImpl::storage_texture_type() {
|
|||
// | TEXTURE_DEPTH_CUBE
|
||||
// | TEXTURE_DEPTH_CUBE_ARRAY
|
||||
Maybe<typ::Type> ParserImpl::depth_texture_type() {
|
||||
if (match(Token::Type::kTextureDepth2d))
|
||||
return typ::Type{
|
||||
builder_.create<ast::DepthTexture>(ast::TextureDimension::k2d),
|
||||
builder_.create<sem::DepthTexture>(ast::TextureDimension::k2d)};
|
||||
Source source;
|
||||
|
||||
if (match(Token::Type::kTextureDepth2dArray))
|
||||
return typ::Type{
|
||||
builder_.create<ast::DepthTexture>(ast::TextureDimension::k2dArray),
|
||||
builder_.create<sem::DepthTexture>(ast::TextureDimension::k2dArray)};
|
||||
if (match(Token::Type::kTextureDepth2d, &source))
|
||||
return builder_.ty.depth_texture(source, ast::TextureDimension::k2d);
|
||||
|
||||
if (match(Token::Type::kTextureDepthCube))
|
||||
return typ::Type{
|
||||
builder_.create<ast::DepthTexture>(ast::TextureDimension::kCube),
|
||||
builder_.create<sem::DepthTexture>(ast::TextureDimension::kCube)};
|
||||
if (match(Token::Type::kTextureDepth2dArray, &source))
|
||||
return builder_.ty.depth_texture(source, ast::TextureDimension::k2dArray);
|
||||
|
||||
if (match(Token::Type::kTextureDepthCubeArray))
|
||||
return typ::Type{
|
||||
builder_.create<ast::DepthTexture>(ast::TextureDimension::kCubeArray),
|
||||
builder_.create<sem::DepthTexture>(ast::TextureDimension::kCubeArray)};
|
||||
if (match(Token::Type::kTextureDepthCube, &source))
|
||||
return builder_.ty.depth_texture(source, ast::TextureDimension::kCube);
|
||||
|
||||
if (match(Token::Type::kTextureDepthCubeArray, &source))
|
||||
return builder_.ty.depth_texture(source, ast::TextureDimension::kCubeArray);
|
||||
|
||||
return Failure::kNoMatch;
|
||||
}
|
||||
|
@ -897,26 +916,15 @@ Expect<ParserImpl::TypedIdentifier> ParserImpl::expect_variable_ident_decl(
|
|||
if (access_decos.size() > 1)
|
||||
return add_error(ident.source, "multiple access decorations not allowed");
|
||||
|
||||
// TODO(crbug.com/tint/724): Remove
|
||||
auto* sem_ty = type.value.sem;
|
||||
for (auto* deco : access_decos) {
|
||||
// If we have an access control decoration then we take it and wrap our
|
||||
// type up with that decoration
|
||||
sem_ty = builder_.create<sem::AccessControl>(
|
||||
deco->As<ast::AccessDecoration>()->value(), sem_ty);
|
||||
}
|
||||
typ::Type ty = type.value;
|
||||
|
||||
auto* ty = type.value.ast;
|
||||
// TODO(crbug.com/tint/724): Remove 'if'
|
||||
if (ty) {
|
||||
for (auto* deco : access_decos) {
|
||||
// If we have an access control decoration then we take it and wrap our
|
||||
// type up with that decoration
|
||||
ty = builder_.create<ast::AccessControl>(
|
||||
ty = builder_.ty.access(deco->source(),
|
||||
deco->As<ast::AccessDecoration>()->value(), ty);
|
||||
}
|
||||
}
|
||||
return TypedIdentifier{typ::Type{ty, sem_ty}, ident.value, ident.source};
|
||||
return TypedIdentifier{ty, ident.value, ident.source};
|
||||
}
|
||||
|
||||
Expect<ast::AccessControl::Access> ParserImpl::expect_access_type() {
|
||||
|
@ -974,14 +982,10 @@ Maybe<typ::Type> ParserImpl::type_alias() {
|
|||
if (!type.matched)
|
||||
return add_error(peek(), "invalid type alias");
|
||||
|
||||
// TODO(crbug.com/tint/724): remove
|
||||
auto* alias = builder_.create<sem::Alias>(
|
||||
builder_.Symbols().Register(name.value), type.value);
|
||||
auto alias = builder_.ty.alias(make_source_range_from(t.source()), name.value,
|
||||
type.value);
|
||||
register_constructed(name.value, alias);
|
||||
|
||||
return typ::Type{builder_.create<ast::Alias>(
|
||||
builder_.Symbols().Register(name.value), type.value),
|
||||
alias};
|
||||
return alias;
|
||||
}
|
||||
|
||||
// type_decl
|
||||
|
@ -1027,29 +1031,29 @@ Maybe<typ::Type> ParserImpl::type_decl() {
|
|||
|
||||
Maybe<typ::Type> ParserImpl::type_decl(ast::DecorationList& decos) {
|
||||
auto t = peek();
|
||||
if (match(Token::Type::kIdentifier)) {
|
||||
Source source;
|
||||
if (match(Token::Type::kIdentifier, &source)) {
|
||||
// TODO(crbug.com/tint/697): Remove
|
||||
auto* ty = get_constructed(t.to_str());
|
||||
if (ty == nullptr)
|
||||
return add_error(t, "unknown constructed type '" + t.to_str() + "'");
|
||||
|
||||
return typ::Type{
|
||||
builder_.create<ast::TypeName>(builder_.Symbols().Register(t.to_str())),
|
||||
return typ::Type{builder_.create<ast::TypeName>(
|
||||
source, builder_.Symbols().Register(t.to_str())),
|
||||
ty};
|
||||
}
|
||||
|
||||
if (match(Token::Type::kBool))
|
||||
return typ::Type{builder_.create<ast::Bool>(),
|
||||
builder_.create<sem::Bool>()};
|
||||
if (match(Token::Type::kBool, &source))
|
||||
return builder_.ty.bool_(source);
|
||||
|
||||
if (match(Token::Type::kF32))
|
||||
return typ::Type{builder_.create<ast::F32>(), builder_.create<sem::F32>()};
|
||||
if (match(Token::Type::kF32, &source))
|
||||
return builder_.ty.f32(source);
|
||||
|
||||
if (match(Token::Type::kI32))
|
||||
return typ::Type{builder_.create<ast::I32>(), builder_.create<sem::I32>()};
|
||||
if (match(Token::Type::kI32, &source))
|
||||
return builder_.ty.i32(source);
|
||||
|
||||
if (match(Token::Type::kU32))
|
||||
return typ::Type{builder_.create<ast::U32>(), builder_.create<sem::U32>()};
|
||||
if (match(Token::Type::kU32, &source))
|
||||
return builder_.ty.u32(source);
|
||||
|
||||
if (t.IsVec2() || t.IsVec3() || t.IsVec4()) {
|
||||
next(); // Consume the peek
|
||||
|
@ -1057,10 +1061,10 @@ Maybe<typ::Type> ParserImpl::type_decl(ast::DecorationList& decos) {
|
|||
}
|
||||
|
||||
if (match(Token::Type::kPtr))
|
||||
return expect_type_decl_pointer();
|
||||
return expect_type_decl_pointer(t);
|
||||
|
||||
if (match(Token::Type::kArray)) {
|
||||
return expect_type_decl_array(std::move(decos));
|
||||
if (match(Token::Type::kArray, &source)) {
|
||||
return expect_type_decl_array(t, std::move(decos));
|
||||
}
|
||||
|
||||
if (t.IsMat2x2() || t.IsMat2x3() || t.IsMat2x4() || t.IsMat3x2() ||
|
||||
|
@ -1088,24 +1092,33 @@ Expect<typ::Type> ParserImpl::expect_type(const std::string& use) {
|
|||
return type.value;
|
||||
}
|
||||
|
||||
Expect<typ::Type> ParserImpl::expect_type_decl_pointer() {
|
||||
Expect<typ::Type> ParserImpl::expect_type_decl_pointer(Token t) {
|
||||
const char* use = "ptr declaration";
|
||||
|
||||
return expect_lt_gt_block(use, [&]() -> Expect<typ::Type> {
|
||||
ast::StorageClass storage_class = ast::StorageClass::kNone;
|
||||
|
||||
auto subtype = expect_lt_gt_block(use, [&]() -> Expect<typ::Type> {
|
||||
auto sc = expect_storage_class(use);
|
||||
if (sc.errored)
|
||||
return Failure::kErrored;
|
||||
storage_class = sc.value;
|
||||
|
||||
if (!expect(use, Token::Type::kComma))
|
||||
return Failure::kErrored;
|
||||
|
||||
auto subtype = expect_type(use);
|
||||
if (subtype.errored)
|
||||
auto type = expect_type(use);
|
||||
if (type.errored)
|
||||
return Failure::kErrored;
|
||||
|
||||
return typ::Type{builder_.create<ast::Pointer>(subtype.value, sc.value),
|
||||
builder_.create<sem::Pointer>(subtype.value, sc.value)};
|
||||
return type.value;
|
||||
});
|
||||
|
||||
if (subtype.errored) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
|
||||
return builder_.ty.pointer(make_source_range_from(t.source()), subtype.value,
|
||||
storage_class);
|
||||
}
|
||||
|
||||
Expect<typ::Type> ParserImpl::expect_type_decl_vector(Token t) {
|
||||
|
@ -1121,20 +1134,22 @@ Expect<typ::Type> ParserImpl::expect_type_decl_vector(Token t) {
|
|||
if (subtype.errored)
|
||||
return Failure::kErrored;
|
||||
|
||||
return typ::Type{builder_.create<ast::Vector>(subtype.value.ast, count),
|
||||
builder_.create<sem::Vector>(subtype.value.sem, count)};
|
||||
return builder_.ty.vec(make_source_range_from(t.source()), subtype.value,
|
||||
count);
|
||||
}
|
||||
|
||||
Expect<typ::Type> ParserImpl::expect_type_decl_array(
|
||||
Token t,
|
||||
ast::DecorationList decos) {
|
||||
const char* use = "array declaration";
|
||||
|
||||
return expect_lt_gt_block(use, [&]() -> Expect<typ::Type> {
|
||||
auto subtype = expect_type(use);
|
||||
if (subtype.errored)
|
||||
uint32_t size = 0;
|
||||
|
||||
auto subtype = expect_lt_gt_block(use, [&]() -> Expect<typ::Type> {
|
||||
auto type = expect_type(use);
|
||||
if (type.errored)
|
||||
return Failure::kErrored;
|
||||
|
||||
uint32_t size = 0;
|
||||
if (match(Token::Type::kComma)) {
|
||||
auto val = expect_nonzero_positive_sint("array size");
|
||||
if (val.errored)
|
||||
|
@ -1142,10 +1157,15 @@ Expect<typ::Type> ParserImpl::expect_type_decl_array(
|
|||
size = val.value;
|
||||
}
|
||||
|
||||
return typ::Type{
|
||||
create<ast::Array>(subtype.value, size, decos),
|
||||
create<sem::ArrayType>(subtype.value, size, std::move(decos))};
|
||||
return type.value;
|
||||
});
|
||||
|
||||
if (subtype.errored) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
|
||||
return builder_.ty.array(make_source_range_from(t.source()), subtype.value,
|
||||
size, std::move(decos));
|
||||
}
|
||||
|
||||
Expect<typ::Type> ParserImpl::expect_type_decl_matrix(Token t) {
|
||||
|
@ -1168,8 +1188,8 @@ Expect<typ::Type> ParserImpl::expect_type_decl_matrix(Token t) {
|
|||
if (subtype.errored)
|
||||
return Failure::kErrored;
|
||||
|
||||
return typ::Type{builder_.create<ast::Matrix>(subtype.value, rows, columns),
|
||||
builder_.create<sem::Matrix>(subtype.value, rows, columns)};
|
||||
return builder_.ty.mat(make_source_range_from(t.source()), subtype.value,
|
||||
columns, rows);
|
||||
}
|
||||
|
||||
// storage_class
|
||||
|
@ -1321,9 +1341,9 @@ Maybe<ast::Function*> ParserImpl::function_decl(ast::DecorationList& decos) {
|
|||
// : type_decl
|
||||
// | VOID
|
||||
Maybe<typ::Type> ParserImpl::function_type_decl() {
|
||||
if (match(Token::Type::kVoid))
|
||||
return typ::Type{builder_.create<ast::Void>(),
|
||||
builder_.create<sem::Void>()};
|
||||
Source source;
|
||||
if (match(Token::Type::kVoid, &source))
|
||||
return builder_.ty.void_(source);
|
||||
|
||||
return type_decl();
|
||||
}
|
||||
|
@ -3385,6 +3405,15 @@ T ParserImpl::without_error(F&& body) {
|
|||
return result;
|
||||
}
|
||||
|
||||
ParserImpl::MultiTokenSource ParserImpl::make_source_range() {
|
||||
return MultiTokenSource(this);
|
||||
}
|
||||
|
||||
ParserImpl::MultiTokenSource ParserImpl::make_source_range_from(
|
||||
const Source& start) {
|
||||
return MultiTokenSource(this, start);
|
||||
}
|
||||
|
||||
} // namespace wgsl
|
||||
} // namespace reader
|
||||
} // namespace tint
|
||||
|
|
|
@ -331,6 +331,8 @@ class ParserImpl {
|
|||
/// @param idx the index of the token to return
|
||||
/// @returns the token `idx` positions ahead without advancing
|
||||
Token peek(size_t idx);
|
||||
/// @returns the last token that was returned by `next()`
|
||||
Token last_token() const;
|
||||
/// Appends an error at `t` with the message `msg`
|
||||
/// @param t the token to associate the error with
|
||||
/// @param msg the error message
|
||||
|
@ -821,9 +823,9 @@ class ParserImpl {
|
|||
/// Used to ensure that all decorations are consumed.
|
||||
bool expect_decorations_consumed(const ast::DecorationList& list);
|
||||
|
||||
Expect<typ::Type> expect_type_decl_pointer();
|
||||
Expect<typ::Type> expect_type_decl_pointer(Token t);
|
||||
Expect<typ::Type> expect_type_decl_vector(Token t);
|
||||
Expect<typ::Type> expect_type_decl_array(ast::DecorationList decos);
|
||||
Expect<typ::Type> expect_type_decl_array(Token t, ast::DecorationList decos);
|
||||
Expect<typ::Type> expect_type_decl_matrix(Token t);
|
||||
|
||||
Expect<typ::Type> expect_type(const std::string& use);
|
||||
|
@ -832,6 +834,10 @@ class ParserImpl {
|
|||
Maybe<ast::Statement*> for_header_initializer();
|
||||
Maybe<ast::Statement*> for_header_continuing();
|
||||
|
||||
class MultiTokenSource;
|
||||
MultiTokenSource make_source_range();
|
||||
MultiTokenSource make_source_range_from(const Source& start);
|
||||
|
||||
/// Creates a new `ast::Node` owned by the Module. When the Module is
|
||||
/// destructed, the `ast::Node` will also be destructed.
|
||||
/// @param args the arguments to pass to the type constructor
|
||||
|
@ -843,6 +849,7 @@ class ParserImpl {
|
|||
|
||||
std::unique_ptr<Lexer> lexer_;
|
||||
std::deque<Token> token_queue_;
|
||||
Token last_token_;
|
||||
bool synchronized_ = true;
|
||||
uint32_t sync_depth_ = 0;
|
||||
std::vector<Token::Type> sync_tokens_;
|
||||
|
|
|
@ -38,6 +38,7 @@ TEST_F(ParserImplTest, DepthTextureType_2d) {
|
|||
ASSERT_TRUE(t->Is<sem::DepthTexture>());
|
||||
EXPECT_EQ(t->As<sem::Texture>()->dim(), ast::TextureDimension::k2d);
|
||||
EXPECT_FALSE(p->has_error());
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 17u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, DepthTextureType_2dArray) {
|
||||
|
@ -50,6 +51,7 @@ TEST_F(ParserImplTest, DepthTextureType_2dArray) {
|
|||
ASSERT_TRUE(t->Is<sem::DepthTexture>());
|
||||
EXPECT_EQ(t->As<sem::Texture>()->dim(), ast::TextureDimension::k2dArray);
|
||||
EXPECT_FALSE(p->has_error());
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 23u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, DepthTextureType_Cube) {
|
||||
|
@ -62,6 +64,7 @@ TEST_F(ParserImplTest, DepthTextureType_Cube) {
|
|||
ASSERT_TRUE(t->Is<sem::DepthTexture>());
|
||||
EXPECT_EQ(t->As<sem::Texture>()->dim(), ast::TextureDimension::kCube);
|
||||
EXPECT_FALSE(p->has_error());
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 19u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, DepthTextureType_CubeArray) {
|
||||
|
@ -74,6 +77,7 @@ TEST_F(ParserImplTest, DepthTextureType_CubeArray) {
|
|||
ASSERT_TRUE(t->Is<sem::DepthTexture>());
|
||||
EXPECT_EQ(t->As<sem::Texture>()->dim(), ast::TextureDimension::kCubeArray);
|
||||
EXPECT_FALSE(p->has_error());
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 25u}}));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -32,6 +32,7 @@ TEST_F(ParserImplTest, ExternalTextureType) {
|
|||
auto t = p->external_texture_type();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 17u}}));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -29,6 +29,7 @@ TEST_F(ParserImplTest, FunctionTypeDecl_Void) {
|
|||
EXPECT_FALSE(e.errored);
|
||||
EXPECT_FALSE(p->has_error()) << p->error();
|
||||
ASSERT_EQ(e.value, v);
|
||||
EXPECT_EQ(e.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 5u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, FunctionTypeDecl_Type) {
|
||||
|
@ -42,6 +43,7 @@ TEST_F(ParserImplTest, FunctionTypeDecl_Type) {
|
|||
EXPECT_FALSE(e.errored);
|
||||
EXPECT_FALSE(p->has_error()) << p->error();
|
||||
ASSERT_EQ(e.value, vec2);
|
||||
EXPECT_EQ(e.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 10u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, FunctionTypeDecl_InvalidType) {
|
||||
|
|
|
@ -37,6 +37,7 @@ TEST_F(ParserImplTest, SamplerType_Sampler) {
|
|||
ASSERT_TRUE(t->Is<sem::Sampler>());
|
||||
EXPECT_FALSE(t->As<sem::Sampler>()->IsComparison());
|
||||
EXPECT_FALSE(p->has_error());
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 8u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, SamplerType_ComparisonSampler) {
|
||||
|
@ -48,6 +49,7 @@ TEST_F(ParserImplTest, SamplerType_ComparisonSampler) {
|
|||
ASSERT_TRUE(t->Is<sem::Sampler>());
|
||||
EXPECT_TRUE(t->As<sem::Sampler>()->IsComparison());
|
||||
EXPECT_FALSE(p->has_error());
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 19u}}));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -39,10 +39,8 @@ TEST_F(ParserImplTest, StructMember_Parses) {
|
|||
EXPECT_EQ(m->type(), i32);
|
||||
EXPECT_EQ(m->decorations().size(), 0u);
|
||||
|
||||
ASSERT_EQ(m->source().range.begin.line, 1u);
|
||||
ASSERT_EQ(m->source().range.begin.column, 1u);
|
||||
ASSERT_EQ(m->source().range.end.line, 1u);
|
||||
ASSERT_EQ(m->source().range.end.column, 2u);
|
||||
EXPECT_EQ(m->source().range, (Source::Range{{1u, 1u}, {1u, 2u}}));
|
||||
EXPECT_EQ(m->type().ast->source().range, (Source::Range{{1u, 5u}, {1u, 8u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, StructMember_ParsesWithOffsetDecoration_DEPRECATED) {
|
||||
|
@ -69,10 +67,9 @@ TEST_F(ParserImplTest, StructMember_ParsesWithOffsetDecoration_DEPRECATED) {
|
|||
m->decorations()[0]->As<ast::StructMemberOffsetDecoration>()->offset(),
|
||||
2u);
|
||||
|
||||
ASSERT_EQ(m->source().range.begin.line, 1u);
|
||||
ASSERT_EQ(m->source().range.begin.column, 15u);
|
||||
ASSERT_EQ(m->source().range.end.line, 1u);
|
||||
ASSERT_EQ(m->source().range.end.column, 16u);
|
||||
EXPECT_EQ(m->source().range, (Source::Range{{1u, 15u}, {1u, 16u}}));
|
||||
EXPECT_EQ(m->type().ast->source().range,
|
||||
(Source::Range{{1u, 19u}, {1u, 22u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, StructMember_ParsesWithAlignDecoration) {
|
||||
|
@ -98,10 +95,9 @@ TEST_F(ParserImplTest, StructMember_ParsesWithAlignDecoration) {
|
|||
EXPECT_EQ(
|
||||
m->decorations()[0]->As<ast::StructMemberAlignDecoration>()->align(), 2u);
|
||||
|
||||
ASSERT_EQ(m->source().range.begin.line, 1u);
|
||||
ASSERT_EQ(m->source().range.begin.column, 14u);
|
||||
ASSERT_EQ(m->source().range.end.line, 1u);
|
||||
ASSERT_EQ(m->source().range.end.column, 15u);
|
||||
EXPECT_EQ(m->source().range, (Source::Range{{1u, 14u}, {1u, 15u}}));
|
||||
EXPECT_EQ(m->type().ast->source().range,
|
||||
(Source::Range{{1u, 18u}, {1u, 21u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, StructMember_ParsesWithSizeDecoration) {
|
||||
|
@ -127,10 +123,9 @@ TEST_F(ParserImplTest, StructMember_ParsesWithSizeDecoration) {
|
|||
EXPECT_EQ(m->decorations()[0]->As<ast::StructMemberSizeDecoration>()->size(),
|
||||
2u);
|
||||
|
||||
ASSERT_EQ(m->source().range.begin.line, 1u);
|
||||
ASSERT_EQ(m->source().range.begin.column, 13u);
|
||||
ASSERT_EQ(m->source().range.end.line, 1u);
|
||||
ASSERT_EQ(m->source().range.end.column, 14u);
|
||||
EXPECT_EQ(m->source().range, (Source::Range{{1u, 13u}, {1u, 14u}}));
|
||||
EXPECT_EQ(m->type().ast->source().range,
|
||||
(Source::Range{{1u, 17u}, {1u, 20u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, StructMember_ParsesWithDecoration) {
|
||||
|
@ -156,10 +151,9 @@ TEST_F(ParserImplTest, StructMember_ParsesWithDecoration) {
|
|||
EXPECT_EQ(m->decorations()[0]->As<ast::StructMemberSizeDecoration>()->size(),
|
||||
2u);
|
||||
|
||||
ASSERT_EQ(m->source().range.begin.line, 1u);
|
||||
ASSERT_EQ(m->source().range.begin.column, 13u);
|
||||
ASSERT_EQ(m->source().range.end.line, 1u);
|
||||
ASSERT_EQ(m->source().range.end.column, 14u);
|
||||
EXPECT_EQ(m->source().range, (Source::Range{{1u, 13u}, {1u, 14u}}));
|
||||
EXPECT_EQ(m->type().ast->source().range,
|
||||
(Source::Range{{1u, 17u}, {1u, 20u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, StructMember_ParsesWithMultipleDecorations) {
|
||||
|
@ -189,10 +183,9 @@ TEST_F(ParserImplTest, StructMember_ParsesWithMultipleDecorations) {
|
|||
EXPECT_EQ(
|
||||
m->decorations()[1]->As<ast::StructMemberAlignDecoration>()->align(), 4u);
|
||||
|
||||
ASSERT_EQ(m->source().range.begin.line, 2u);
|
||||
ASSERT_EQ(m->source().range.begin.column, 14u);
|
||||
ASSERT_EQ(m->source().range.end.line, 2u);
|
||||
ASSERT_EQ(m->source().range.end.column, 15u);
|
||||
EXPECT_EQ(m->source().range, (Source::Range{{2u, 14u}, {2u, 15u}}));
|
||||
EXPECT_EQ(m->type().ast->source().range,
|
||||
(Source::Range{{2u, 18u}, {2u, 21u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, StructMember_InvalidDecoration) {
|
||||
|
|
|
@ -40,6 +40,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_Sampler) {
|
|||
ASSERT_NE(t.value, nullptr);
|
||||
ASSERT_TRUE(t->Is<sem::Sampler>());
|
||||
ASSERT_FALSE(t->As<sem::Sampler>()->IsComparison());
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 8u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TextureSamplerTypes_SamplerComparison) {
|
||||
|
@ -51,6 +52,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_SamplerComparison) {
|
|||
ASSERT_NE(t.value, nullptr);
|
||||
ASSERT_TRUE(t->Is<sem::Sampler>());
|
||||
ASSERT_TRUE(t->As<sem::Sampler>()->IsComparison());
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 19u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TextureSamplerTypes_DepthTexture) {
|
||||
|
@ -63,6 +65,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_DepthTexture) {
|
|||
ASSERT_TRUE(t->Is<sem::Texture>());
|
||||
ASSERT_TRUE(t->Is<sem::DepthTexture>());
|
||||
EXPECT_EQ(t->As<sem::Texture>()->dim(), ast::TextureDimension::k2d);
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 17u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_F32) {
|
||||
|
@ -76,6 +79,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_F32) {
|
|||
ASSERT_TRUE(t->Is<sem::SampledTexture>());
|
||||
ASSERT_TRUE(t->As<sem::SampledTexture>()->type()->Is<sem::F32>());
|
||||
EXPECT_EQ(t->As<sem::Texture>()->dim(), ast::TextureDimension::k1d);
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 16u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_I32) {
|
||||
|
@ -89,6 +93,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_I32) {
|
|||
ASSERT_TRUE(t->Is<sem::SampledTexture>());
|
||||
ASSERT_TRUE(t->As<sem::SampledTexture>()->type()->Is<sem::I32>());
|
||||
EXPECT_EQ(t->As<sem::Texture>()->dim(), ast::TextureDimension::k2d);
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 16u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_U32) {
|
||||
|
@ -102,6 +107,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_U32) {
|
|||
ASSERT_TRUE(t->Is<sem::SampledTexture>());
|
||||
ASSERT_TRUE(t->As<sem::SampledTexture>()->type()->Is<sem::U32>());
|
||||
EXPECT_EQ(t->As<sem::Texture>()->dim(), ast::TextureDimension::k3d);
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 16u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_Invalid) {
|
||||
|
@ -155,6 +161,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_I32) {
|
|||
ASSERT_TRUE(t->Is<sem::MultisampledTexture>());
|
||||
ASSERT_TRUE(t->As<sem::MultisampledTexture>()->type()->Is<sem::I32>());
|
||||
EXPECT_EQ(t->As<sem::Texture>()->dim(), ast::TextureDimension::k2d);
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 29u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_Invalid) {
|
||||
|
@ -210,6 +217,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Readonly1dR8Unorm) {
|
|||
EXPECT_EQ(t->As<sem::StorageTexture>()->image_format(),
|
||||
ast::ImageFormat::kR8Unorm);
|
||||
EXPECT_EQ(t->As<sem::Texture>()->dim(), ast::TextureDimension::k1d);
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 28u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Writeonly2dR16Float) {
|
||||
|
@ -225,6 +233,7 @@ TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Writeonly2dR16Float) {
|
|||
EXPECT_EQ(t->As<sem::StorageTexture>()->image_format(),
|
||||
ast::ImageFormat::kR16Float);
|
||||
EXPECT_EQ(t->As<sem::Texture>()->dim(), ast::TextureDimension::k2d);
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 29u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_InvalidType) {
|
||||
|
|
|
@ -33,6 +33,8 @@ TEST_F(ParserImplTest, TypeDecl_ParsesType) {
|
|||
auto* alias = t->As<sem::Alias>();
|
||||
ASSERT_TRUE(alias->type()->Is<sem::I32>());
|
||||
ASSERT_EQ(alias->type(), i32);
|
||||
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 13u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_ParsesStruct_Ident) {
|
||||
|
@ -54,6 +56,8 @@ TEST_F(ParserImplTest, TypeDecl_ParsesStruct_Ident) {
|
|||
auto* s = alias->type()->As<sem::StructType>();
|
||||
EXPECT_EQ(s->impl()->name(), p->builder().Symbols().Get("B"));
|
||||
EXPECT_EQ(s->impl()->name(), p->builder().Symbols().Get("B"));
|
||||
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 11u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_MissingIdent) {
|
||||
|
|
|
@ -50,6 +50,7 @@ TEST_F(ParserImplTest, TypeDecl_Identifier) {
|
|||
auto* alias = t->As<sem::Alias>();
|
||||
EXPECT_EQ(p->builder().Symbols().NameFor(alias->symbol()), "A");
|
||||
EXPECT_EQ(alias->type(), int_type);
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 2u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Identifier_NotFound) {
|
||||
|
@ -75,6 +76,7 @@ TEST_F(ParserImplTest, TypeDecl_Bool) {
|
|||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
EXPECT_EQ(t.value, bool_type);
|
||||
ASSERT_TRUE(t->Is<sem::Bool>());
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 5u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_F32) {
|
||||
|
@ -89,6 +91,7 @@ TEST_F(ParserImplTest, TypeDecl_F32) {
|
|||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
EXPECT_EQ(t.value, float_type);
|
||||
ASSERT_TRUE(t->Is<sem::F32>());
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 4u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_I32) {
|
||||
|
@ -103,6 +106,7 @@ TEST_F(ParserImplTest, TypeDecl_I32) {
|
|||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
EXPECT_EQ(t.value, int_type);
|
||||
ASSERT_TRUE(t->Is<sem::I32>());
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 4u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_U32) {
|
||||
|
@ -117,11 +121,13 @@ TEST_F(ParserImplTest, TypeDecl_U32) {
|
|||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
EXPECT_EQ(t.value, uint_type);
|
||||
ASSERT_TRUE(t->Is<sem::U32>());
|
||||
EXPECT_EQ(t.value.ast->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);
|
||||
|
@ -140,12 +146,16 @@ TEST_P(VecTest, Parse) {
|
|||
ASSERT_FALSE(p->has_error());
|
||||
EXPECT_TRUE(t->Is<sem::Vector>());
|
||||
EXPECT_EQ(t->As<sem::Vector>()->size(), params.count);
|
||||
EXPECT_EQ(t.value.ast->source().range, params.range);
|
||||
}
|
||||
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
ParserImplTest,
|
||||
VecTest,
|
||||
testing::Values(VecData{"vec2<f32>", 2},
|
||||
VecData{"vec3<f32>", 3},
|
||||
VecData{"vec4<f32>", 4}));
|
||||
testing::Values(VecData{"vec2<f32>", 2, Source::Range{{1u, 1u}, {1u, 10u}}},
|
||||
VecData{"vec3<f32>", 3, Source::Range{{1u, 1u}, {1u, 10u}}},
|
||||
VecData{"vec4<f32>", 4, Source::Range{{1u, 1u}, {1u, 10u}}}
|
||||
|
||||
));
|
||||
|
||||
class VecMissingGreaterThanTest : public ParserImplTestWithParam<VecData> {};
|
||||
|
||||
|
@ -161,9 +171,9 @@ TEST_P(VecMissingGreaterThanTest, Handles_Missing_GreaterThan) {
|
|||
}
|
||||
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
|
||||
VecMissingGreaterThanTest,
|
||||
testing::Values(VecData{"vec2<f32", 2},
|
||||
VecData{"vec3<f32", 3},
|
||||
VecData{"vec4<f32", 4}));
|
||||
testing::Values(VecData{"vec2<f32", 2, {}},
|
||||
VecData{"vec3<f32", 3, {}},
|
||||
VecData{"vec4<f32", 4, {}}));
|
||||
|
||||
class VecMissingLessThanTest : public ParserImplTestWithParam<VecData> {};
|
||||
|
||||
|
@ -179,9 +189,9 @@ TEST_P(VecMissingLessThanTest, Handles_Missing_GreaterThan) {
|
|||
}
|
||||
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
|
||||
VecMissingLessThanTest,
|
||||
testing::Values(VecData{"vec2", 2},
|
||||
VecData{"vec3", 3},
|
||||
VecData{"vec4", 4}));
|
||||
testing::Values(VecData{"vec2", 2, {}},
|
||||
VecData{"vec3", 3, {}},
|
||||
VecData{"vec4", 4, {}}));
|
||||
|
||||
class VecBadType : public ParserImplTestWithParam<VecData> {};
|
||||
|
||||
|
@ -197,9 +207,9 @@ TEST_P(VecBadType, Handles_Unknown_Type) {
|
|||
}
|
||||
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
|
||||
VecBadType,
|
||||
testing::Values(VecData{"vec2<unknown", 2},
|
||||
VecData{"vec3<unknown", 3},
|
||||
VecData{"vec4<unknown", 4}));
|
||||
testing::Values(VecData{"vec2<unknown", 2, {}},
|
||||
VecData{"vec3<unknown", 3, {}},
|
||||
VecData{"vec4<unknown", 4, {}}));
|
||||
|
||||
class VecMissingType : public ParserImplTestWithParam<VecData> {};
|
||||
|
||||
|
@ -215,9 +225,9 @@ TEST_P(VecMissingType, Handles_Missing_Type) {
|
|||
}
|
||||
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
|
||||
VecMissingType,
|
||||
testing::Values(VecData{"vec2<>", 2},
|
||||
VecData{"vec3<>", 3},
|
||||
VecData{"vec4<>", 4}));
|
||||
testing::Values(VecData{"vec2<>", 2, {}},
|
||||
VecData{"vec3<>", 3, {}},
|
||||
VecData{"vec4<>", 4, {}}));
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Ptr) {
|
||||
auto p = parser("ptr<function, f32>");
|
||||
|
@ -231,6 +241,7 @@ TEST_F(ParserImplTest, TypeDecl_Ptr) {
|
|||
auto* ptr = t->As<sem::Pointer>();
|
||||
ASSERT_TRUE(ptr->type()->Is<sem::F32>());
|
||||
ASSERT_EQ(ptr->storage_class(), ast::StorageClass::kFunction);
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 19u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Ptr_ToVec) {
|
||||
|
@ -249,6 +260,7 @@ TEST_F(ParserImplTest, TypeDecl_Ptr_ToVec) {
|
|||
auto* vec = ptr->type()->As<sem::Vector>();
|
||||
ASSERT_EQ(vec->size(), 2u);
|
||||
ASSERT_TRUE(vec->type()->Is<sem::F32>());
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 25}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Ptr_MissingLessThan) {
|
||||
|
@ -345,6 +357,7 @@ TEST_F(ParserImplTest, TypeDecl_Array) {
|
|||
ASSERT_EQ(a->size(), 5u);
|
||||
ASSERT_TRUE(a->type()->Is<sem::F32>());
|
||||
EXPECT_EQ(a->decorations().size(), 0u);
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 14u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_Stride) {
|
||||
|
@ -365,6 +378,7 @@ TEST_F(ParserImplTest, TypeDecl_Array_Stride) {
|
|||
auto* stride = a->decorations()[0];
|
||||
ASSERT_TRUE(stride->Is<ast::StrideDecoration>());
|
||||
ASSERT_EQ(stride->As<ast::StrideDecoration>()->stride(), 16u);
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 16u}, {1u, 29u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_Runtime_Stride) {
|
||||
|
@ -384,6 +398,7 @@ TEST_F(ParserImplTest, TypeDecl_Array_Runtime_Stride) {
|
|||
auto* stride = a->decorations()[0];
|
||||
ASSERT_TRUE(stride->Is<ast::StrideDecoration>());
|
||||
ASSERT_EQ(stride->As<ast::StrideDecoration>()->stride(), 16u);
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 16u}, {1u, 26u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_MultipleDecorations_OneBlock) {
|
||||
|
@ -405,6 +420,7 @@ TEST_F(ParserImplTest, TypeDecl_Array_MultipleDecorations_OneBlock) {
|
|||
EXPECT_EQ(decos[0]->As<ast::StrideDecoration>()->stride(), 16u);
|
||||
EXPECT_TRUE(decos[1]->Is<ast::StrideDecoration>());
|
||||
EXPECT_EQ(decos[1]->As<ast::StrideDecoration>()->stride(), 32u);
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 28u}, {1u, 38u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_MultipleDecorations_MultipleBlocks) {
|
||||
|
@ -426,6 +442,7 @@ TEST_F(ParserImplTest, TypeDecl_Array_MultipleDecorations_MultipleBlocks) {
|
|||
EXPECT_EQ(decos[0]->As<ast::StrideDecoration>()->stride(), 16u);
|
||||
EXPECT_TRUE(decos[1]->Is<ast::StrideDecoration>());
|
||||
EXPECT_EQ(decos[1]->As<ast::StrideDecoration>()->stride(), 32u);
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 31u}, {1u, 41u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_Decoration_MissingArray) {
|
||||
|
@ -522,6 +539,7 @@ TEST_F(ParserImplTest, TypeDecl_Array_Runtime) {
|
|||
auto* a = t->As<sem::ArrayType>();
|
||||
ASSERT_TRUE(a->IsRuntimeArray());
|
||||
ASSERT_TRUE(a->type()->Is<sem::U32>());
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 11u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_Runtime_Vec) {
|
||||
|
@ -536,6 +554,7 @@ TEST_F(ParserImplTest, TypeDecl_Array_Runtime_Vec) {
|
|||
auto* a = t->As<sem::ArrayType>();
|
||||
ASSERT_TRUE(a->IsRuntimeArray());
|
||||
ASSERT_TRUE(a->type()->is_unsigned_integer_vector());
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 17u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_BadType) {
|
||||
|
@ -612,6 +631,7 @@ 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);
|
||||
|
@ -632,18 +652,21 @@ TEST_P(MatrixTest, Parse) {
|
|||
auto* mat = t->As<sem::Matrix>();
|
||||
EXPECT_EQ(mat->rows(), params.rows);
|
||||
EXPECT_EQ(mat->columns(), params.columns);
|
||||
EXPECT_EQ(t.value.ast->source().range, params.range);
|
||||
}
|
||||
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
ParserImplTest,
|
||||
MatrixTest,
|
||||
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}));
|
||||
testing::Values(
|
||||
MatrixData{"mat2x2<f32>", 2, 2, Source::Range{{1u, 1u}, {1u, 12u}}},
|
||||
MatrixData{"mat2x3<f32>", 2, 3, Source::Range{{1u, 1u}, {1u, 12u}}},
|
||||
MatrixData{"mat2x4<f32>", 2, 4, Source::Range{{1u, 1u}, {1u, 12u}}},
|
||||
MatrixData{"mat3x2<f32>", 3, 2, Source::Range{{1u, 1u}, {1u, 12u}}},
|
||||
MatrixData{"mat3x3<f32>", 3, 3, Source::Range{{1u, 1u}, {1u, 12u}}},
|
||||
MatrixData{"mat3x4<f32>", 3, 4, Source::Range{{1u, 1u}, {1u, 12u}}},
|
||||
MatrixData{"mat4x2<f32>", 4, 2, Source::Range{{1u, 1u}, {1u, 12u}}},
|
||||
MatrixData{"mat4x3<f32>", 4, 3, Source::Range{{1u, 1u}, {1u, 12u}}},
|
||||
MatrixData{"mat4x4<f32>", 4, 4, Source::Range{{1u, 1u}, {1u, 12u}}}));
|
||||
|
||||
class MatrixMissingGreaterThanTest
|
||||
: public ParserImplTestWithParam<MatrixData> {};
|
||||
|
@ -660,15 +683,15 @@ TEST_P(MatrixMissingGreaterThanTest, Handles_Missing_GreaterThan) {
|
|||
}
|
||||
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
|
||||
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}));
|
||||
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 MatrixMissingLessThanTest : public ParserImplTestWithParam<MatrixData> {};
|
||||
|
||||
|
@ -684,15 +707,15 @@ TEST_P(MatrixMissingLessThanTest, Handles_Missing_GreaterThan) {
|
|||
}
|
||||
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
|
||||
MatrixMissingLessThanTest,
|
||||
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}));
|
||||
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 MatrixBadType : public ParserImplTestWithParam<MatrixData> {};
|
||||
|
||||
|
@ -706,17 +729,18 @@ TEST_P(MatrixBadType, Handles_Unknown_Type) {
|
|||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:8: unknown constructed type 'unknown'");
|
||||
}
|
||||
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
ParserImplTest,
|
||||
MatrixBadType,
|
||||
testing::Values(MatrixData{"mat2x2<unknown>", 2, 2},
|
||||
MatrixData{"mat2x3<unknown>", 2, 3},
|
||||
MatrixData{"mat2x4<unknown>", 2, 4},
|
||||
MatrixData{"mat3x2<unknown>", 3, 2},
|
||||
MatrixData{"mat3x3<unknown>", 3, 3},
|
||||
MatrixData{"mat3x4<unknown>", 3, 4},
|
||||
MatrixData{"mat4x2<unknown>", 4, 2},
|
||||
MatrixData{"mat4x3<unknown>", 4, 3},
|
||||
MatrixData{"mat4x4<unknown>", 4, 4}));
|
||||
testing::Values(MatrixData{"mat2x2<unknown>", 2, 2, {}},
|
||||
MatrixData{"mat2x3<unknown>", 2, 3, {}},
|
||||
MatrixData{"mat2x4<unknown>", 2, 4, {}},
|
||||
MatrixData{"mat3x2<unknown>", 3, 2, {}},
|
||||
MatrixData{"mat3x3<unknown>", 3, 3, {}},
|
||||
MatrixData{"mat3x4<unknown>", 3, 4, {}},
|
||||
MatrixData{"mat4x2<unknown>", 4, 2, {}},
|
||||
MatrixData{"mat4x3<unknown>", 4, 3, {}},
|
||||
MatrixData{"mat4x4<unknown>", 4, 4, {}}));
|
||||
|
||||
class MatrixMissingType : public ParserImplTestWithParam<MatrixData> {};
|
||||
|
||||
|
@ -732,15 +756,15 @@ TEST_P(MatrixMissingType, Handles_Missing_Type) {
|
|||
}
|
||||
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
|
||||
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}));
|
||||
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, TypeDecl_Sampler) {
|
||||
auto p = parser("sampler");
|
||||
|
@ -755,6 +779,7 @@ TEST_F(ParserImplTest, TypeDecl_Sampler) {
|
|||
EXPECT_EQ(t.value, type);
|
||||
ASSERT_TRUE(t->Is<sem::Sampler>());
|
||||
ASSERT_FALSE(t->As<sem::Sampler>()->IsComparison());
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 8u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Texture) {
|
||||
|
@ -772,6 +797,7 @@ TEST_F(ParserImplTest, TypeDecl_Texture) {
|
|||
ASSERT_TRUE(t->Is<sem::Texture>());
|
||||
ASSERT_TRUE(t->Is<sem::SampledTexture>());
|
||||
ASSERT_TRUE(t->As<sem::SampledTexture>()->type()->Is<sem::F32>());
|
||||
EXPECT_EQ(t.value.ast->source().range, (Source::Range{{1u, 1u}, {1u, 18u}}));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -29,10 +29,8 @@ TEST_F(ParserImplTest, VariableDecl_Parses) {
|
|||
EXPECT_NE(v->type, nullptr);
|
||||
EXPECT_TRUE(v->type->Is<sem::F32>());
|
||||
|
||||
EXPECT_EQ(v->source.range.begin.line, 1u);
|
||||
EXPECT_EQ(v->source.range.begin.column, 5u);
|
||||
EXPECT_EQ(v->source.range.end.line, 1u);
|
||||
EXPECT_EQ(v->source.range.end.column, 11u);
|
||||
EXPECT_EQ(v->source.range, (Source::Range{{1u, 5u}, {1u, 11u}}));
|
||||
EXPECT_EQ(v->type.ast->source().range, (Source::Range{{1u, 14u}, {1u, 17u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, VariableDecl_MissingVar) {
|
||||
|
|
|
@ -30,10 +30,9 @@ TEST_F(ParserImplTest, VariableIdentDecl_Parses) {
|
|||
ASSERT_NE(decl->type, nullptr);
|
||||
ASSERT_TRUE(decl->type->Is<sem::F32>());
|
||||
|
||||
ASSERT_EQ(decl->source.range.begin.line, 1u);
|
||||
ASSERT_EQ(decl->source.range.begin.column, 1u);
|
||||
ASSERT_EQ(decl->source.range.end.line, 1u);
|
||||
ASSERT_EQ(decl->source.range.end.column, 7u);
|
||||
EXPECT_EQ(decl->source.range, (Source::Range{{1u, 1u}, {1u, 7u}}));
|
||||
EXPECT_EQ(decl->type.ast->source().range,
|
||||
(Source::Range{{1u, 10u}, {1u, 13u}}));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, VariableIdentDecl_MissingIdent) {
|
||||
|
|
|
@ -84,13 +84,6 @@ class ScopedAssignment {
|
|||
T old_value_;
|
||||
};
|
||||
|
||||
// Helper function that returns the range union of two source locations. The
|
||||
// `start` and `end` locations are assumed to refer to the same source file.
|
||||
Source CombineSourceRange(const Source& start, const Source& end) {
|
||||
return Source(Source::Range(start.range.begin, end.range.end),
|
||||
start.file_path, start.file_content);
|
||||
}
|
||||
|
||||
bool IsValidStorageTextureDimension(ast::TextureDimension dim) {
|
||||
switch (dim) {
|
||||
case ast::TextureDimension::k1d:
|
||||
|
@ -1392,7 +1385,7 @@ bool Resolver::ValidateVectorConstructor(const sem::Vector* vec_type,
|
|||
"attempted to construct '" +
|
||||
vec_type->FriendlyName(builder_->Symbols()) + "' with " +
|
||||
std::to_string(value_cardinality_sum) + " component(s)",
|
||||
CombineSourceRange(values_start, values_end));
|
||||
Source::Combine(values_start, values_end));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -1414,7 +1407,7 @@ bool Resolver::ValidateMatrixConstructor(const sem::Matrix* matrix_type,
|
|||
VectorPretty(matrix_type->rows(), elem_type) + "' arguments in '" +
|
||||
matrix_type->FriendlyName(builder_->Symbols()) +
|
||||
"' constructor, found " + std::to_string(values.size()),
|
||||
CombineSourceRange(values_start, values_end));
|
||||
Source::Combine(values_start, values_end));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
82
src/source.h
82
src/source.h
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
namespace tint {
|
||||
|
@ -65,6 +66,27 @@ class Source {
|
|||
size_t line = 0;
|
||||
/// the 1-based column number. 0 represents no column information.
|
||||
size_t column = 0;
|
||||
|
||||
/// Returns true of `this` location is lexicographically less than `rhs`
|
||||
/// @param rhs location to compare against
|
||||
/// @returns true if `this` < `rhs`
|
||||
inline bool operator<(const Source::Location& rhs) {
|
||||
return std::tie(line, column) < std::tie(rhs.line, rhs.column);
|
||||
}
|
||||
|
||||
/// Returns true of `this` location is equal to `rhs`
|
||||
/// @param rhs location to compare against
|
||||
/// @returns true if `this` == `rhs`
|
||||
inline bool operator==(const Location& rhs) const {
|
||||
return line == rhs.line && column == rhs.column;
|
||||
}
|
||||
|
||||
/// Returns true of `this` location is not equal to `rhs`
|
||||
/// @param rhs location to compare against
|
||||
/// @returns true if `this` != `rhs`
|
||||
inline bool operator!=(const Location& rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
};
|
||||
|
||||
/// Range holds a Location interval described by [begin, end).
|
||||
|
@ -75,12 +97,14 @@ class Source {
|
|||
|
||||
/// Constructs a zero-length Range starting at `loc`
|
||||
/// @param loc the start and end location for the range
|
||||
inline explicit Range(const Location& loc) : begin(loc), end(loc) {}
|
||||
inline constexpr explicit Range(const Location& loc)
|
||||
: begin(loc), end(loc) {}
|
||||
|
||||
/// Constructs the Range beginning at `b` and ending at `e`
|
||||
/// @param b the range start location
|
||||
/// @param e the range end location
|
||||
inline Range(const Location& b, const Location& e) : begin(b), end(e) {}
|
||||
inline constexpr Range(const Location& b, const Location& e)
|
||||
: begin(b), end(e) {}
|
||||
|
||||
/// Return a column-shifted Range
|
||||
/// @param n the number of characters to shift by
|
||||
|
@ -89,6 +113,18 @@ class Source {
|
|||
return Range{{begin.line, begin.column + n}, {end.line, end.column + n}};
|
||||
}
|
||||
|
||||
/// Returns true of `this` range is not equal to `rhs`
|
||||
/// @param rhs range to compare against
|
||||
/// @returns true if `this` != `rhs`
|
||||
inline bool operator==(const Range& rhs) const {
|
||||
return begin == rhs.begin && end == rhs.end;
|
||||
}
|
||||
|
||||
/// Returns true of `this` range is equal to `rhs`
|
||||
/// @param rhs range to compare against
|
||||
/// @returns true if `this` == `rhs`
|
||||
inline bool operator!=(const Range& rhs) const { return !(*this == rhs); }
|
||||
|
||||
/// The location of the first character in the range.
|
||||
Location begin;
|
||||
/// The location of one-past the last character in the range.
|
||||
|
@ -139,6 +175,29 @@ class Source {
|
|||
return Source(range + n, file_path, file_content);
|
||||
}
|
||||
|
||||
/// Returns true of `this` Source is lexicographically less than `rhs`
|
||||
/// @param rhs source to compare against
|
||||
/// @returns true if `this` < `rhs`
|
||||
inline bool operator<(const Source& rhs) {
|
||||
if (file_path != rhs.file_path) {
|
||||
return false;
|
||||
}
|
||||
if (file_content != rhs.file_content) {
|
||||
return false;
|
||||
}
|
||||
return range.begin < rhs.range.begin;
|
||||
}
|
||||
|
||||
/// Helper function that returns the range union of two source locations. The
|
||||
/// `start` and `end` locations are assumed to refer to the same source file.
|
||||
/// @param start the start source of the range
|
||||
/// @param end the end source of the range
|
||||
/// @returns the combined source
|
||||
inline static Source Combine(const Source& start, const Source& end) {
|
||||
return Source(Source::Range(start.range.begin, end.range.end),
|
||||
start.file_path, start.file_content);
|
||||
}
|
||||
|
||||
/// range is the span of text this source refers to in #file_path
|
||||
Range range;
|
||||
/// file is the optional file path this source refers to
|
||||
|
@ -147,6 +206,25 @@ class Source {
|
|||
const FileContent* file_content = nullptr;
|
||||
};
|
||||
|
||||
/// Writes the Source::Location to the std::ostream.
|
||||
/// @param out the std::ostream to write to
|
||||
/// @param loc the location to write
|
||||
/// @returns out so calls can be chained
|
||||
inline std::ostream& operator<<(std::ostream& out,
|
||||
const Source::Location& loc) {
|
||||
out << loc.line << ":" << loc.column;
|
||||
return out;
|
||||
}
|
||||
|
||||
/// Writes the Source::Range to the std::ostream.
|
||||
/// @param out the std::ostream to write to
|
||||
/// @param range the range to write
|
||||
/// @returns out so calls can be chained
|
||||
inline std::ostream& operator<<(std::ostream& out, const Source::Range& range) {
|
||||
out << "[" << range.begin << ", " << range.end << "]";
|
||||
return out;
|
||||
}
|
||||
|
||||
/// Writes the Source to the std::ostream.
|
||||
/// @param out the std::ostream to write to
|
||||
/// @param source the source to write
|
||||
|
|
|
@ -33,6 +33,7 @@ class Alias;
|
|||
class Array;
|
||||
class Bool;
|
||||
class DepthTexture;
|
||||
class ExternalTexture;
|
||||
class F32;
|
||||
class I32;
|
||||
class Matrix;
|
||||
|
@ -54,6 +55,7 @@ class Alias;
|
|||
class ArrayType;
|
||||
class Bool;
|
||||
class DepthTexture;
|
||||
class ExternalTexture;
|
||||
class F32;
|
||||
class I32;
|
||||
class Matrix;
|
||||
|
@ -145,6 +147,7 @@ using Alias = TypePair<ast::Alias, sem::Alias>;
|
|||
using Array = TypePair<ast::Array, sem::ArrayType>;
|
||||
using Bool = TypePair<ast::Bool, sem::Bool>;
|
||||
using DepthTexture = TypePair<ast::DepthTexture, sem::DepthTexture>;
|
||||
using ExternalTexture = TypePair<ast::ExternalTexture, sem::ExternalTexture>;
|
||||
using F32 = TypePair<ast::F32, sem::F32>;
|
||||
using I32 = TypePair<ast::I32, sem::I32>;
|
||||
using Matrix = TypePair<ast::Matrix, sem::Matrix>;
|
||||
|
|
Loading…
Reference in New Issue