tint/reader: Enable 'const' parsing for unit-tests
This enables the WGSL parsing of 'const' for only tint_unittests, allowing code to be split up into smaller chunks for review. Once all the logic is submitted to handle 'const', the test-only flag will be removed, and 'const' will be enabled for production. Bug: tint:1580 Change-Id: I3189b6bd15445ecc3fa1cd6f568885e7ba3c91c0 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/94680 Reviewed-by: David Neto <dneto@google.com> Commit-Queue: Ben Clayton <bclayton@google.com> Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
511529f082
commit
e48ef8ef90
|
@ -34,6 +34,10 @@ Const::Const(Const&&) = default;
|
||||||
|
|
||||||
Const::~Const() = default;
|
Const::~Const() = default;
|
||||||
|
|
||||||
|
const char* Const::Kind() const {
|
||||||
|
return "const";
|
||||||
|
}
|
||||||
|
|
||||||
const Const* Const::Clone(CloneContext* ctx) const {
|
const Const* Const::Clone(CloneContext* ctx) const {
|
||||||
auto src = ctx->Clone(source);
|
auto src = ctx->Clone(source);
|
||||||
auto sym = ctx->Clone(symbol);
|
auto sym = ctx->Clone(symbol);
|
||||||
|
|
|
@ -52,6 +52,9 @@ class Const final : public Castable<Const, Variable> {
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~Const() override;
|
~Const() override;
|
||||||
|
|
||||||
|
/// @returns "const"
|
||||||
|
const char* Kind() const override;
|
||||||
|
|
||||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||||
/// `ctx`.
|
/// `ctx`.
|
||||||
/// @param ctx the clone context
|
/// @param ctx the clone context
|
||||||
|
|
|
@ -34,6 +34,10 @@ Let::Let(Let&&) = default;
|
||||||
|
|
||||||
Let::~Let() = default;
|
Let::~Let() = default;
|
||||||
|
|
||||||
|
const char* Let::Kind() const {
|
||||||
|
return "let";
|
||||||
|
}
|
||||||
|
|
||||||
const Let* Let::Clone(CloneContext* ctx) const {
|
const Let* Let::Clone(CloneContext* ctx) const {
|
||||||
auto src = ctx->Clone(source);
|
auto src = ctx->Clone(source);
|
||||||
auto sym = ctx->Clone(symbol);
|
auto sym = ctx->Clone(symbol);
|
||||||
|
|
|
@ -49,6 +49,9 @@ class Let final : public Castable<Let, Variable> {
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~Let() override;
|
~Let() override;
|
||||||
|
|
||||||
|
/// @returns "let"
|
||||||
|
const char* Kind() const override;
|
||||||
|
|
||||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||||
/// `ctx`.
|
/// `ctx`.
|
||||||
/// @param ctx the clone context
|
/// @param ctx the clone context
|
||||||
|
|
|
@ -32,6 +32,10 @@ Override::Override(Override&&) = default;
|
||||||
|
|
||||||
Override::~Override() = default;
|
Override::~Override() = default;
|
||||||
|
|
||||||
|
const char* Override::Kind() const {
|
||||||
|
return "override";
|
||||||
|
}
|
||||||
|
|
||||||
const Override* Override::Clone(CloneContext* ctx) const {
|
const Override* Override::Clone(CloneContext* ctx) const {
|
||||||
auto src = ctx->Clone(source);
|
auto src = ctx->Clone(source);
|
||||||
auto sym = ctx->Clone(symbol);
|
auto sym = ctx->Clone(symbol);
|
||||||
|
|
|
@ -50,6 +50,9 @@ class Override final : public Castable<Override, Variable> {
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~Override() override;
|
~Override() override;
|
||||||
|
|
||||||
|
/// @returns "override"
|
||||||
|
const char* Kind() const override;
|
||||||
|
|
||||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||||
/// `ctx`.
|
/// `ctx`.
|
||||||
/// @param ctx the clone context
|
/// @param ctx the clone context
|
||||||
|
|
|
@ -31,6 +31,10 @@ Parameter::Parameter(Parameter&&) = default;
|
||||||
|
|
||||||
Parameter::~Parameter() = default;
|
Parameter::~Parameter() = default;
|
||||||
|
|
||||||
|
const char* Parameter::Kind() const {
|
||||||
|
return "parameter";
|
||||||
|
}
|
||||||
|
|
||||||
const Parameter* Parameter::Clone(CloneContext* ctx) const {
|
const Parameter* Parameter::Clone(CloneContext* ctx) const {
|
||||||
auto src = ctx->Clone(source);
|
auto src = ctx->Clone(source);
|
||||||
auto sym = ctx->Clone(symbol);
|
auto sym = ctx->Clone(symbol);
|
||||||
|
|
|
@ -51,6 +51,9 @@ class Parameter final : public Castable<Parameter, Variable> {
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~Parameter() override;
|
~Parameter() override;
|
||||||
|
|
||||||
|
/// @returns "parameter"
|
||||||
|
const char* Kind() const override;
|
||||||
|
|
||||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||||
/// `ctx`.
|
/// `ctx`.
|
||||||
/// @param ctx the clone context
|
/// @param ctx the clone context
|
||||||
|
|
|
@ -36,6 +36,10 @@ Var::Var(Var&&) = default;
|
||||||
|
|
||||||
Var::~Var() = default;
|
Var::~Var() = default;
|
||||||
|
|
||||||
|
const char* Var::Kind() const {
|
||||||
|
return "var";
|
||||||
|
}
|
||||||
|
|
||||||
const Var* Var::Clone(CloneContext* ctx) const {
|
const Var* Var::Clone(CloneContext* ctx) const {
|
||||||
auto src = ctx->Clone(source);
|
auto src = ctx->Clone(source);
|
||||||
auto sym = ctx->Clone(symbol);
|
auto sym = ctx->Clone(symbol);
|
||||||
|
|
|
@ -65,6 +65,9 @@ class Var final : public Castable<Var, Variable> {
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~Var() override;
|
~Var() override;
|
||||||
|
|
||||||
|
/// @returns "var"
|
||||||
|
const char* Kind() const override;
|
||||||
|
|
||||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||||
/// `ctx`.
|
/// `ctx`.
|
||||||
/// @param ctx the clone context
|
/// @param ctx the clone context
|
||||||
|
|
|
@ -77,6 +77,10 @@ class Variable : public Castable<Variable, Node> {
|
||||||
/// @note binding points should only be applied to Var and Parameter types.
|
/// @note binding points should only be applied to Var and Parameter types.
|
||||||
VariableBindingPoint BindingPoint() const;
|
VariableBindingPoint BindingPoint() const;
|
||||||
|
|
||||||
|
/// @returns the kind of the variable, which can be used in diagnostics
|
||||||
|
/// e.g. "var", "let", "const", etc
|
||||||
|
virtual const char* Kind() const = 0;
|
||||||
|
|
||||||
/// The variable symbol
|
/// The variable symbol
|
||||||
const Symbol symbol;
|
const Symbol symbol;
|
||||||
|
|
||||||
|
|
|
@ -144,18 +144,18 @@ TEST_P(LineCommentTerminatorTest, Terminators) {
|
||||||
// Test that line comments are ended by blankspace characters other than
|
// Test that line comments are ended by blankspace characters other than
|
||||||
// space, horizontal tab, left-to-right mark, and right-to-left mark.
|
// space, horizontal tab, left-to-right mark, and right-to-left mark.
|
||||||
auto* c = GetParam();
|
auto* c = GetParam();
|
||||||
std::string src = "let// This is a comment";
|
std::string src = "const// This is a comment";
|
||||||
src += c;
|
src += c;
|
||||||
src += "ident";
|
src += "ident";
|
||||||
Source::File file("", src);
|
Source::File file("", src);
|
||||||
Lexer l(&file);
|
Lexer l(&file);
|
||||||
|
|
||||||
auto t = l.next();
|
auto t = l.next();
|
||||||
EXPECT_TRUE(t.Is(Token::Type::kLet));
|
EXPECT_TRUE(t.Is(Token::Type::kConst));
|
||||||
EXPECT_EQ(t.source().range.begin.line, 1u);
|
EXPECT_EQ(t.source().range.begin.line, 1u);
|
||||||
EXPECT_EQ(t.source().range.begin.column, 1u);
|
EXPECT_EQ(t.source().range.begin.column, 1u);
|
||||||
EXPECT_EQ(t.source().range.end.line, 1u);
|
EXPECT_EQ(t.source().range.end.line, 1u);
|
||||||
EXPECT_EQ(t.source().range.end.column, 4u);
|
EXPECT_EQ(t.source().range.end.column, 6u);
|
||||||
|
|
||||||
auto is_same_line = [](std::string_view v) {
|
auto is_same_line = [](std::string_view v) {
|
||||||
return v == kSpace || v == kHTab || v == kL2R || v == kR2L;
|
return v == kSpace || v == kHTab || v == kL2R || v == kR2L;
|
||||||
|
|
|
@ -47,6 +47,9 @@
|
||||||
namespace tint::reader::wgsl {
|
namespace tint::reader::wgsl {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
// TODO(crbug.com/tint/1580): Remove when 'const' is fully implemented.
|
||||||
|
bool const_enabled = false;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using Expect = ParserImpl::Expect<T>;
|
using Expect = ParserImpl::Expect<T>;
|
||||||
|
|
||||||
|
@ -245,6 +248,11 @@ ParserImpl::ParserImpl(Source::File const* file) : lexer_(std::make_unique<Lexer
|
||||||
|
|
||||||
ParserImpl::~ParserImpl() = default;
|
ParserImpl::~ParserImpl() = default;
|
||||||
|
|
||||||
|
// TODO(crbug.com/tint/1580): Remove when 'const' is fully implemented.
|
||||||
|
void ParserImpl::EnableConst() {
|
||||||
|
const_enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
ParserImpl::Failure::Errored ParserImpl::add_error(const Source& source,
|
ParserImpl::Failure::Errored ParserImpl::add_error(const Source& source,
|
||||||
std::string_view err,
|
std::string_view err,
|
||||||
std::string_view use) {
|
std::string_view use) {
|
||||||
|
@ -437,9 +445,13 @@ Maybe<bool> ParserImpl::global_decl() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gc.matched) {
|
if (gc.matched) {
|
||||||
if (!expect("'let' declaration", Token::Type::kSemicolon)) {
|
// Avoid the cost of the string allocation for the common no-error case
|
||||||
|
if (!peek().Is(Token::Type::kSemicolon)) {
|
||||||
|
std::string kind = gc->Kind();
|
||||||
|
if (!expect("'" + kind + "' declaration", Token::Type::kSemicolon)) {
|
||||||
return Failure::kErrored;
|
return Failure::kErrored;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
builder_.AST().AddGlobalVariable(gc.value);
|
builder_.AST().AddGlobalVariable(gc.value);
|
||||||
return true;
|
return true;
|
||||||
|
@ -561,10 +573,14 @@ Maybe<const ast::Variable*> ParserImpl::global_variable_decl(ast::AttributeList&
|
||||||
// global_const_initializer
|
// global_const_initializer
|
||||||
// : EQUAL const_expr
|
// : EQUAL const_expr
|
||||||
Maybe<const ast::Variable*> ParserImpl::global_constant_decl(ast::AttributeList& attrs) {
|
Maybe<const ast::Variable*> ParserImpl::global_constant_decl(ast::AttributeList& attrs) {
|
||||||
|
bool is_const = false;
|
||||||
bool is_overridable = false;
|
bool is_overridable = false;
|
||||||
const char* use = nullptr;
|
const char* use = nullptr;
|
||||||
if (match(Token::Type::kLet)) {
|
if (match(Token::Type::kLet)) {
|
||||||
use = "'let' declaration";
|
use = "'let' declaration";
|
||||||
|
} else if (const_enabled && match(Token::Type::kConst)) {
|
||||||
|
use = "'const' declaration";
|
||||||
|
is_const = true;
|
||||||
} else if (match(Token::Type::kOverride)) {
|
} else if (match(Token::Type::kOverride)) {
|
||||||
use = "'override' declaration";
|
use = "'override' declaration";
|
||||||
is_overridable = true;
|
is_overridable = true;
|
||||||
|
@ -596,6 +612,13 @@ Maybe<const ast::Variable*> ParserImpl::global_constant_decl(ast::AttributeList&
|
||||||
initializer = std::move(init.value);
|
initializer = std::move(init.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_const) {
|
||||||
|
return create<ast::Const>(decl->source, // source
|
||||||
|
builder_.Symbols().Register(decl->name), // symbol
|
||||||
|
decl->type, // type
|
||||||
|
initializer, // constructor
|
||||||
|
std::move(attrs)); // attributes
|
||||||
|
}
|
||||||
if (is_overridable) {
|
if (is_overridable) {
|
||||||
return create<ast::Override>(decl->source, // source
|
return create<ast::Override>(decl->source, // source
|
||||||
builder_.Symbols().Register(decl->name), // symbol
|
builder_.Symbols().Register(decl->name), // symbol
|
||||||
|
@ -1769,6 +1792,34 @@ Maybe<const ast::ReturnStatement*> ParserImpl::return_stmt() {
|
||||||
// | variable_decl EQUAL logical_or_expression
|
// | variable_decl EQUAL logical_or_expression
|
||||||
// | CONST variable_ident_decl EQUAL logical_or_expression
|
// | CONST variable_ident_decl EQUAL logical_or_expression
|
||||||
Maybe<const ast::VariableDeclStatement*> ParserImpl::variable_stmt() {
|
Maybe<const ast::VariableDeclStatement*> ParserImpl::variable_stmt() {
|
||||||
|
if (const_enabled && match(Token::Type::kConst)) {
|
||||||
|
auto decl = expect_variable_ident_decl("'const' declaration",
|
||||||
|
/*allow_inferred = */ true);
|
||||||
|
if (decl.errored) {
|
||||||
|
return Failure::kErrored;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!expect("'const' declaration", Token::Type::kEqual)) {
|
||||||
|
return Failure::kErrored;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto constructor = logical_or_expression();
|
||||||
|
if (constructor.errored) {
|
||||||
|
return Failure::kErrored;
|
||||||
|
}
|
||||||
|
if (!constructor.matched) {
|
||||||
|
return add_error(peek(), "missing constructor for 'const' declaration");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* const_ = create<ast::Const>(decl->source, // source
|
||||||
|
builder_.Symbols().Register(decl->name), // symbol
|
||||||
|
decl->type, // type
|
||||||
|
constructor.value, // constructor
|
||||||
|
ast::AttributeList{}); // attributes
|
||||||
|
|
||||||
|
return create<ast::VariableDeclStatement>(decl->source, const_);
|
||||||
|
}
|
||||||
|
|
||||||
if (match(Token::Type::kLet)) {
|
if (match(Token::Type::kLet)) {
|
||||||
auto decl = expect_variable_ident_decl("'let' declaration",
|
auto decl = expect_variable_ident_decl("'let' declaration",
|
||||||
/*allow_inferred = */ true);
|
/*allow_inferred = */ true);
|
||||||
|
|
|
@ -72,6 +72,11 @@ class ParserImpl {
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/// A temporary bodge to enable unit-testing of 'const' variable types while still under active
|
||||||
|
/// development.
|
||||||
|
// TODO(crbug.com/tint/1580): Remove when 'const' is fully implemented.
|
||||||
|
static void EnableConst();
|
||||||
|
|
||||||
/// Expect is the return type of the parser methods that are expected to
|
/// Expect is the return type of the parser methods that are expected to
|
||||||
/// return a parsed value of type T, unless there was an parse error.
|
/// return a parsed value of type T, unless there was an parse error.
|
||||||
/// In the case of a parse error the called method will have called
|
/// In the case of a parse error the called method will have called
|
||||||
|
|
|
@ -471,6 +471,107 @@ test.wgsl:3:3 error: statement found outside of function body
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplErrorTest, GlobalDeclConstInvalidIdentifier) {
|
TEST_F(ParserImplErrorTest, GlobalDeclConstInvalidIdentifier) {
|
||||||
|
EXPECT("const ^ : i32 = 1;",
|
||||||
|
R"(test.wgsl:1:7 error: expected identifier for 'const' declaration
|
||||||
|
const ^ : i32 = 1;
|
||||||
|
^
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ParserImplErrorTest, GlobalDeclConstMissingSemicolon) {
|
||||||
|
EXPECT("const i : i32 = 1",
|
||||||
|
R"(test.wgsl:1:18 error: expected ';' for 'const' declaration
|
||||||
|
const i : i32 = 1
|
||||||
|
^
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ParserImplErrorTest, GlobalDeclConstMissingLParen) {
|
||||||
|
EXPECT("const i : vec2<i32> = vec2<i32>;",
|
||||||
|
R"(test.wgsl:1:32 error: expected '(' for type constructor
|
||||||
|
const i : vec2<i32> = vec2<i32>;
|
||||||
|
^
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ParserImplErrorTest, GlobalDeclConstMissingRParen) {
|
||||||
|
EXPECT("const i : vec2<i32> = vec2<i32>(1., 2.;",
|
||||||
|
R"(test.wgsl:1:39 error: expected ')' for type constructor
|
||||||
|
const i : vec2<i32> = vec2<i32>(1., 2.;
|
||||||
|
^
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ParserImplErrorTest, GlobalDeclConstBadConstLiteral) {
|
||||||
|
EXPECT("const i : vec2<i32> = vec2<i32>(!);",
|
||||||
|
R"(test.wgsl:1:33 error: unable to parse const_expr
|
||||||
|
const i : vec2<i32> = vec2<i32>(!);
|
||||||
|
^
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ParserImplErrorTest, GlobalDeclConstBadConstLiteralSpaceLessThan) {
|
||||||
|
EXPECT("const i = 1 < 2;",
|
||||||
|
R"(test.wgsl:1:13 error: expected ';' for 'const' declaration
|
||||||
|
const i = 1 < 2;
|
||||||
|
^
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ParserImplErrorTest, GlobalDeclConstNotConstExpr) {
|
||||||
|
EXPECT(
|
||||||
|
"const a = 1;\n"
|
||||||
|
"const b = a;",
|
||||||
|
R"(test.wgsl:2:11 error: unable to parse const_expr
|
||||||
|
const b = a;
|
||||||
|
^
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ParserImplErrorTest, GlobalDeclConstExprMaxDepth) {
|
||||||
|
uint32_t kMaxDepth = 128;
|
||||||
|
|
||||||
|
std::stringstream src;
|
||||||
|
std::stringstream mkr;
|
||||||
|
src << "const i : i32 = ";
|
||||||
|
mkr << " ";
|
||||||
|
for (size_t i = 0; i < kMaxDepth + 8; i++) {
|
||||||
|
src << "f32(";
|
||||||
|
if (i < kMaxDepth) {
|
||||||
|
mkr << " ";
|
||||||
|
} else if (i == kMaxDepth) {
|
||||||
|
mkr << "^^^";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
src << "1.0";
|
||||||
|
for (size_t i = 0; i < 200; i++) {
|
||||||
|
src << ")";
|
||||||
|
}
|
||||||
|
src << ";";
|
||||||
|
std::stringstream err;
|
||||||
|
err << "test.wgsl:1:529 error: maximum parser recursive depth reached\n"
|
||||||
|
<< src.str() << "\n"
|
||||||
|
<< mkr.str() << "\n";
|
||||||
|
EXPECT(src.str().c_str(), err.str().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ParserImplErrorTest, GlobalDeclConstExprMissingLParen) {
|
||||||
|
EXPECT("const i : vec2<i32> = vec2<i32> 1, 2);",
|
||||||
|
R"(test.wgsl:1:33 error: expected '(' for type constructor
|
||||||
|
const i : vec2<i32> = vec2<i32> 1, 2);
|
||||||
|
^
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ParserImplErrorTest, GlobalDeclConstExprMissingRParen) {
|
||||||
|
EXPECT("const i : vec2<i32> = vec2<i32>(1, 2;",
|
||||||
|
R"(test.wgsl:1:37 error: expected ')' for type constructor
|
||||||
|
const i : vec2<i32> = vec2<i32>(1, 2;
|
||||||
|
^
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ParserImplErrorTest, GlobalDeclLetInvalidIdentifier) {
|
||||||
EXPECT("let ^ : i32 = 1;",
|
EXPECT("let ^ : i32 = 1;",
|
||||||
R"(test.wgsl:1:5 error: expected identifier for 'let' declaration
|
R"(test.wgsl:1:5 error: expected identifier for 'let' declaration
|
||||||
let ^ : i32 = 1;
|
let ^ : i32 = 1;
|
||||||
|
@ -478,7 +579,7 @@ let ^ : i32 = 1;
|
||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplErrorTest, GlobalDeclConstMissingSemicolon) {
|
TEST_F(ParserImplErrorTest, GlobalDeclLetMissingSemicolon) {
|
||||||
EXPECT("let i : i32 = 1",
|
EXPECT("let i : i32 = 1",
|
||||||
R"(test.wgsl:1:16 error: expected ';' for 'let' declaration
|
R"(test.wgsl:1:16 error: expected ';' for 'let' declaration
|
||||||
let i : i32 = 1
|
let i : i32 = 1
|
||||||
|
@ -486,7 +587,7 @@ let i : i32 = 1
|
||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplErrorTest, GlobalDeclConstMissingLParen) {
|
TEST_F(ParserImplErrorTest, GlobalDeclLetMissingLParen) {
|
||||||
EXPECT("let i : vec2<i32> = vec2<i32>;",
|
EXPECT("let i : vec2<i32> = vec2<i32>;",
|
||||||
R"(test.wgsl:1:30 error: expected '(' for type constructor
|
R"(test.wgsl:1:30 error: expected '(' for type constructor
|
||||||
let i : vec2<i32> = vec2<i32>;
|
let i : vec2<i32> = vec2<i32>;
|
||||||
|
@ -494,7 +595,7 @@ let i : vec2<i32> = vec2<i32>;
|
||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplErrorTest, GlobalDeclConstMissingRParen) {
|
TEST_F(ParserImplErrorTest, GlobalDeclLetMissingRParen) {
|
||||||
EXPECT("let i : vec2<i32> = vec2<i32>(1., 2.;",
|
EXPECT("let i : vec2<i32> = vec2<i32>(1., 2.;",
|
||||||
R"(test.wgsl:1:37 error: expected ')' for type constructor
|
R"(test.wgsl:1:37 error: expected ')' for type constructor
|
||||||
let i : vec2<i32> = vec2<i32>(1., 2.;
|
let i : vec2<i32> = vec2<i32>(1., 2.;
|
||||||
|
@ -502,7 +603,7 @@ let i : vec2<i32> = vec2<i32>(1., 2.;
|
||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplErrorTest, GlobalDeclConstBadConstLiteral) {
|
TEST_F(ParserImplErrorTest, GlobalDeclLetBadConstLiteral) {
|
||||||
EXPECT("let i : vec2<i32> = vec2<i32>(!);",
|
EXPECT("let i : vec2<i32> = vec2<i32>(!);",
|
||||||
R"(test.wgsl:1:31 error: unable to parse const_expr
|
R"(test.wgsl:1:31 error: unable to parse const_expr
|
||||||
let i : vec2<i32> = vec2<i32>(!);
|
let i : vec2<i32> = vec2<i32>(!);
|
||||||
|
@ -510,7 +611,7 @@ let i : vec2<i32> = vec2<i32>(!);
|
||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplErrorTest, GlobalDeclConstBadConstLiteralSpaceLessThan) {
|
TEST_F(ParserImplErrorTest, GlobalDeclLetBadConstLiteralSpaceLessThan) {
|
||||||
EXPECT("let i = 1 < 2;",
|
EXPECT("let i = 1 < 2;",
|
||||||
R"(test.wgsl:1:11 error: expected ';' for 'let' declaration
|
R"(test.wgsl:1:11 error: expected ';' for 'let' declaration
|
||||||
let i = 1 < 2;
|
let i = 1 < 2;
|
||||||
|
@ -518,7 +619,7 @@ let i = 1 < 2;
|
||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplErrorTest, GlobalDeclConstNotConstExpr) {
|
TEST_F(ParserImplErrorTest, GlobalDeclLetNotConstExpr) {
|
||||||
EXPECT(
|
EXPECT(
|
||||||
"let a = 1;\n"
|
"let a = 1;\n"
|
||||||
"let b = a;",
|
"let b = a;",
|
||||||
|
@ -528,7 +629,7 @@ let b = a;
|
||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplErrorTest, GlobalDeclConstExprMaxDepth) {
|
TEST_F(ParserImplErrorTest, GlobalDeclLetExprMaxDepth) {
|
||||||
uint32_t kMaxDepth = 128;
|
uint32_t kMaxDepth = 128;
|
||||||
|
|
||||||
std::stringstream src;
|
std::stringstream src;
|
||||||
|
@ -555,7 +656,7 @@ TEST_F(ParserImplErrorTest, GlobalDeclConstExprMaxDepth) {
|
||||||
EXPECT(src.str().c_str(), err.str().c_str());
|
EXPECT(src.str().c_str(), err.str().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplErrorTest, GlobalDeclConstExprMissingLParen) {
|
TEST_F(ParserImplErrorTest, GlobalDeclLetExprMissingLParen) {
|
||||||
EXPECT("let i : vec2<i32> = vec2<i32> 1, 2);",
|
EXPECT("let i : vec2<i32> = vec2<i32> 1, 2);",
|
||||||
R"(test.wgsl:1:31 error: expected '(' for type constructor
|
R"(test.wgsl:1:31 error: expected '(' for type constructor
|
||||||
let i : vec2<i32> = vec2<i32> 1, 2);
|
let i : vec2<i32> = vec2<i32> 1, 2);
|
||||||
|
@ -563,7 +664,7 @@ let i : vec2<i32> = vec2<i32> 1, 2);
|
||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplErrorTest, GlobalDeclConstExprMissingRParen) {
|
TEST_F(ParserImplErrorTest, GlobalDeclLetExprMissingRParen) {
|
||||||
EXPECT("let i : vec2<i32> = vec2<i32>(1, 2;",
|
EXPECT("let i : vec2<i32> = vec2<i32>(1, 2;",
|
||||||
R"(test.wgsl:1:35 error: expected ')' for type constructor
|
R"(test.wgsl:1:35 error: expected ')' for type constructor
|
||||||
let i : vec2<i32> = vec2<i32>(1, 2;
|
let i : vec2<i32> = vec2<i32>(1, 2;
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
namespace tint::reader::wgsl {
|
namespace tint::reader::wgsl {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
TEST_F(ParserImplTest, GlobalConstantDecl) {
|
TEST_F(ParserImplTest, GlobalLetDecl) {
|
||||||
auto p = parser("let a : f32 = 1.");
|
auto p = parser("let a : f32 = 1.");
|
||||||
auto attrs = p->attribute_list();
|
auto attrs = p->attribute_list();
|
||||||
EXPECT_FALSE(attrs.errored);
|
EXPECT_FALSE(attrs.errored);
|
||||||
|
@ -43,7 +43,7 @@ TEST_F(ParserImplTest, GlobalConstantDecl) {
|
||||||
EXPECT_TRUE(let->constructor->Is<ast::LiteralExpression>());
|
EXPECT_TRUE(let->constructor->Is<ast::LiteralExpression>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, GlobalConstantDecl_Inferred) {
|
TEST_F(ParserImplTest, GlobalLetDecl_Inferred) {
|
||||||
auto p = parser("let a = 1.");
|
auto p = parser("let a = 1.");
|
||||||
auto attrs = p->attribute_list();
|
auto attrs = p->attribute_list();
|
||||||
EXPECT_FALSE(attrs.errored);
|
EXPECT_FALSE(attrs.errored);
|
||||||
|
@ -67,7 +67,7 @@ TEST_F(ParserImplTest, GlobalConstantDecl_Inferred) {
|
||||||
EXPECT_TRUE(let->constructor->Is<ast::LiteralExpression>());
|
EXPECT_TRUE(let->constructor->Is<ast::LiteralExpression>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, GlobalConstantDecl_InvalidExpression) {
|
TEST_F(ParserImplTest, GlobalLetDecl_InvalidExpression) {
|
||||||
auto p = parser("let a : f32 = if (a) {}");
|
auto p = parser("let a : f32 = if (a) {}");
|
||||||
auto attrs = p->attribute_list();
|
auto attrs = p->attribute_list();
|
||||||
EXPECT_FALSE(attrs.errored);
|
EXPECT_FALSE(attrs.errored);
|
||||||
|
@ -80,7 +80,7 @@ TEST_F(ParserImplTest, GlobalConstantDecl_InvalidExpression) {
|
||||||
EXPECT_EQ(p->error(), "1:15: invalid type for const_expr");
|
EXPECT_EQ(p->error(), "1:15: invalid type for const_expr");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, GlobalConstantDecl_MissingExpression) {
|
TEST_F(ParserImplTest, GlobalLetDecl_MissingExpression) {
|
||||||
auto p = parser("let a : f32 =");
|
auto p = parser("let a : f32 =");
|
||||||
auto attrs = p->attribute_list();
|
auto attrs = p->attribute_list();
|
||||||
EXPECT_FALSE(attrs.errored);
|
EXPECT_FALSE(attrs.errored);
|
||||||
|
@ -93,7 +93,82 @@ TEST_F(ParserImplTest, GlobalConstantDecl_MissingExpression) {
|
||||||
EXPECT_EQ(p->error(), "1:14: unable to parse const_expr");
|
EXPECT_EQ(p->error(), "1:14: unable to parse const_expr");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, GlobalConstantDec_Override_WithId) {
|
TEST_F(ParserImplTest, GlobalConstDecl) {
|
||||||
|
auto p = parser("const a : f32 = 1.");
|
||||||
|
auto attrs = p->attribute_list();
|
||||||
|
EXPECT_FALSE(attrs.errored);
|
||||||
|
EXPECT_FALSE(attrs.matched);
|
||||||
|
auto e = p->global_constant_decl(attrs.value);
|
||||||
|
EXPECT_FALSE(p->has_error()) << p->error();
|
||||||
|
EXPECT_TRUE(e.matched);
|
||||||
|
EXPECT_FALSE(e.errored);
|
||||||
|
auto* c = e.value->As<ast::Const>();
|
||||||
|
ASSERT_NE(c, nullptr);
|
||||||
|
|
||||||
|
EXPECT_EQ(c->symbol, p->builder().Symbols().Get("a"));
|
||||||
|
ASSERT_NE(c->type, nullptr);
|
||||||
|
EXPECT_TRUE(c->type->Is<ast::F32>());
|
||||||
|
|
||||||
|
EXPECT_EQ(c->source.range.begin.line, 1u);
|
||||||
|
EXPECT_EQ(c->source.range.begin.column, 7u);
|
||||||
|
EXPECT_EQ(c->source.range.end.line, 1u);
|
||||||
|
EXPECT_EQ(c->source.range.end.column, 8u);
|
||||||
|
|
||||||
|
ASSERT_NE(c->constructor, nullptr);
|
||||||
|
EXPECT_TRUE(c->constructor->Is<ast::LiteralExpression>());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ParserImplTest, GlobalConstDecl_Inferred) {
|
||||||
|
auto p = parser("const a = 1.");
|
||||||
|
auto attrs = p->attribute_list();
|
||||||
|
EXPECT_FALSE(attrs.errored);
|
||||||
|
EXPECT_FALSE(attrs.matched);
|
||||||
|
auto e = p->global_constant_decl(attrs.value);
|
||||||
|
EXPECT_FALSE(p->has_error()) << p->error();
|
||||||
|
EXPECT_TRUE(e.matched);
|
||||||
|
EXPECT_FALSE(e.errored);
|
||||||
|
auto* c = e.value->As<ast::Const>();
|
||||||
|
ASSERT_NE(c, nullptr);
|
||||||
|
|
||||||
|
EXPECT_EQ(c->symbol, p->builder().Symbols().Get("a"));
|
||||||
|
EXPECT_EQ(c->type, nullptr);
|
||||||
|
|
||||||
|
EXPECT_EQ(c->source.range.begin.line, 1u);
|
||||||
|
EXPECT_EQ(c->source.range.begin.column, 7u);
|
||||||
|
EXPECT_EQ(c->source.range.end.line, 1u);
|
||||||
|
EXPECT_EQ(c->source.range.end.column, 8u);
|
||||||
|
|
||||||
|
ASSERT_NE(c->constructor, nullptr);
|
||||||
|
EXPECT_TRUE(c->constructor->Is<ast::LiteralExpression>());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ParserImplTest, GlobalConstDecl_InvalidExpression) {
|
||||||
|
auto p = parser("const a : f32 = if (a) {}");
|
||||||
|
auto attrs = p->attribute_list();
|
||||||
|
EXPECT_FALSE(attrs.errored);
|
||||||
|
EXPECT_FALSE(attrs.matched);
|
||||||
|
auto e = p->global_constant_decl(attrs.value);
|
||||||
|
EXPECT_TRUE(p->has_error());
|
||||||
|
EXPECT_TRUE(e.errored);
|
||||||
|
EXPECT_FALSE(e.matched);
|
||||||
|
EXPECT_EQ(e.value, nullptr);
|
||||||
|
EXPECT_EQ(p->error(), "1:17: invalid type for const_expr");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ParserImplTest, GlobalConstDecl_MissingExpression) {
|
||||||
|
auto p = parser("const a : f32 =");
|
||||||
|
auto attrs = p->attribute_list();
|
||||||
|
EXPECT_FALSE(attrs.errored);
|
||||||
|
EXPECT_FALSE(attrs.matched);
|
||||||
|
auto e = p->global_constant_decl(attrs.value);
|
||||||
|
EXPECT_TRUE(p->has_error());
|
||||||
|
EXPECT_TRUE(e.errored);
|
||||||
|
EXPECT_FALSE(e.matched);
|
||||||
|
EXPECT_EQ(e.value, nullptr);
|
||||||
|
EXPECT_EQ(p->error(), "1:16: unable to parse const_expr");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ParserImplTest, GlobalOverrideDecl_WithId) {
|
||||||
auto p = parser("@id(7) override a : f32 = 1.");
|
auto p = parser("@id(7) override a : f32 = 1.");
|
||||||
auto attrs = p->attribute_list();
|
auto attrs = p->attribute_list();
|
||||||
EXPECT_FALSE(attrs.errored);
|
EXPECT_FALSE(attrs.errored);
|
||||||
|
@ -123,7 +198,7 @@ TEST_F(ParserImplTest, GlobalConstantDec_Override_WithId) {
|
||||||
EXPECT_EQ(override_attr->value, 7u);
|
EXPECT_EQ(override_attr->value, 7u);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, GlobalConstantDec_Override_WithoutId) {
|
TEST_F(ParserImplTest, GlobalOverrideDecl_WithoutId) {
|
||||||
auto p = parser("override a : f32 = 1.");
|
auto p = parser("override a : f32 = 1.");
|
||||||
auto attrs = p->attribute_list();
|
auto attrs = p->attribute_list();
|
||||||
EXPECT_FALSE(attrs.errored);
|
EXPECT_FALSE(attrs.errored);
|
||||||
|
@ -152,7 +227,7 @@ TEST_F(ParserImplTest, GlobalConstantDec_Override_WithoutId) {
|
||||||
ASSERT_EQ(id_attr, nullptr);
|
ASSERT_EQ(id_attr, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, GlobalConstantDec_Override_MissingId) {
|
TEST_F(ParserImplTest, GlobalOverrideDecl_MissingId) {
|
||||||
auto p = parser("@id() override a : f32 = 1.");
|
auto p = parser("@id() override a : f32 = 1.");
|
||||||
auto attrs = p->attribute_list();
|
auto attrs = p->attribute_list();
|
||||||
EXPECT_TRUE(attrs.errored);
|
EXPECT_TRUE(attrs.errored);
|
||||||
|
@ -168,7 +243,7 @@ TEST_F(ParserImplTest, GlobalConstantDec_Override_MissingId) {
|
||||||
EXPECT_EQ(p->error(), "1:5: expected signed integer literal for id attribute");
|
EXPECT_EQ(p->error(), "1:5: expected signed integer literal for id attribute");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, GlobalConstantDec_Override_InvalidId) {
|
TEST_F(ParserImplTest, GlobalOverrideDecl_InvalidId) {
|
||||||
auto p = parser("@id(-7) override a : f32 = 1.");
|
auto p = parser("@id(-7) override a : f32 = 1.");
|
||||||
auto attrs = p->attribute_list();
|
auto attrs = p->attribute_list();
|
||||||
EXPECT_TRUE(attrs.errored);
|
EXPECT_TRUE(attrs.errored);
|
||||||
|
|
|
@ -49,7 +49,7 @@ TEST_F(ParserImplTest, GlobalDecl_GlobalVariable_MissingSemicolon) {
|
||||||
EXPECT_EQ(p->error(), "1:27: expected ';' for variable declaration");
|
EXPECT_EQ(p->error(), "1:27: expected ';' for variable declaration");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, GlobalDecl_GlobalConstant) {
|
TEST_F(ParserImplTest, GlobalDecl_GlobalLet) {
|
||||||
auto p = parser("let a : i32 = 2;");
|
auto p = parser("let a : i32 = 2;");
|
||||||
p->global_decl();
|
p->global_decl();
|
||||||
ASSERT_FALSE(p->has_error()) << p->error();
|
ASSERT_FALSE(p->has_error()) << p->error();
|
||||||
|
@ -61,27 +61,60 @@ TEST_F(ParserImplTest, GlobalDecl_GlobalConstant) {
|
||||||
EXPECT_EQ(v->symbol, program.Symbols().Get("a"));
|
EXPECT_EQ(v->symbol, program.Symbols().Get("a"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, GlobalDecl_GlobalConstant_MissingInitializer) {
|
TEST_F(ParserImplTest, GlobalDecl_GlobalLet_MissingInitializer) {
|
||||||
auto p = parser("let a : vec2<i32>;");
|
auto p = parser("let a : vec2<i32>;");
|
||||||
p->global_decl();
|
p->global_decl();
|
||||||
ASSERT_TRUE(p->has_error());
|
ASSERT_TRUE(p->has_error());
|
||||||
EXPECT_EQ(p->error(), "1:18: expected '=' for 'let' declaration");
|
EXPECT_EQ(p->error(), "1:18: expected '=' for 'let' declaration");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, GlobalDecl_GlobalConstant_Invalid) {
|
TEST_F(ParserImplTest, GlobalDecl_GlobalLet_Invalid) {
|
||||||
auto p = parser("let a : vec2<i32> 1.0;");
|
auto p = parser("let a : vec2<i32> 1.0;");
|
||||||
p->global_decl();
|
p->global_decl();
|
||||||
ASSERT_TRUE(p->has_error());
|
ASSERT_TRUE(p->has_error());
|
||||||
EXPECT_EQ(p->error(), "1:19: expected '=' for 'let' declaration");
|
EXPECT_EQ(p->error(), "1:19: expected '=' for 'let' declaration");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, GlobalDecl_GlobalConstant_MissingSemicolon) {
|
TEST_F(ParserImplTest, GlobalDecl_GlobalLet_MissingSemicolon) {
|
||||||
auto p = parser("let a : vec2<i32> = vec2<i32>(1, 2)");
|
auto p = parser("let a : vec2<i32> = vec2<i32>(1, 2)");
|
||||||
p->global_decl();
|
p->global_decl();
|
||||||
ASSERT_TRUE(p->has_error());
|
ASSERT_TRUE(p->has_error());
|
||||||
EXPECT_EQ(p->error(), "1:36: expected ';' for 'let' declaration");
|
EXPECT_EQ(p->error(), "1:36: expected ';' for 'let' declaration");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ParserImplTest, GlobalDecl_GlobalConst) {
|
||||||
|
auto p = parser("const a : i32 = 2;");
|
||||||
|
p->global_decl();
|
||||||
|
ASSERT_FALSE(p->has_error()) << p->error();
|
||||||
|
|
||||||
|
auto program = p->program();
|
||||||
|
ASSERT_EQ(program.AST().GlobalVariables().size(), 1u);
|
||||||
|
|
||||||
|
auto* v = program.AST().GlobalVariables()[0];
|
||||||
|
EXPECT_EQ(v->symbol, program.Symbols().Get("a"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ParserImplTest, GlobalDecl_GlobalConst_MissingInitializer) {
|
||||||
|
auto p = parser("const a : vec2<i32>;");
|
||||||
|
p->global_decl();
|
||||||
|
ASSERT_TRUE(p->has_error());
|
||||||
|
EXPECT_EQ(p->error(), "1:20: expected '=' for 'const' declaration");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ParserImplTest, GlobalDecl_GlobalConst_Invalid) {
|
||||||
|
auto p = parser("const a : vec2<i32> 1.0;");
|
||||||
|
p->global_decl();
|
||||||
|
ASSERT_TRUE(p->has_error());
|
||||||
|
EXPECT_EQ(p->error(), "1:21: expected '=' for 'const' declaration");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ParserImplTest, GlobalDecl_GlobalConst_MissingSemicolon) {
|
||||||
|
auto p = parser("const a : vec2<i32> = vec2<i32>(1, 2)");
|
||||||
|
p->global_decl();
|
||||||
|
ASSERT_TRUE(p->has_error());
|
||||||
|
EXPECT_EQ(p->error(), "1:38: expected ';' for 'const' declaration");
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, GlobalDecl_TypeAlias) {
|
TEST_F(ParserImplTest, GlobalDecl_TypeAlias) {
|
||||||
auto p = parser("type A = i32;");
|
auto p = parser("type A = i32;");
|
||||||
p->global_decl();
|
p->global_decl();
|
||||||
|
|
|
@ -32,6 +32,13 @@ TEST_P(ParserImplReservedKeywordTest, ModuleLet) {
|
||||||
EXPECT_TRUE(p->has_error());
|
EXPECT_TRUE(p->has_error());
|
||||||
EXPECT_EQ(p->error(), "1:5: '" + name + "' is a reserved keyword");
|
EXPECT_EQ(p->error(), "1:5: '" + name + "' is a reserved keyword");
|
||||||
}
|
}
|
||||||
|
TEST_P(ParserImplReservedKeywordTest, ModuleConst) {
|
||||||
|
auto name = GetParam();
|
||||||
|
auto p = parser("const " + name + " : i32 = 1;");
|
||||||
|
EXPECT_FALSE(p->Parse());
|
||||||
|
EXPECT_TRUE(p->has_error());
|
||||||
|
EXPECT_EQ(p->error(), "1:7: '" + name + "' is a reserved keyword");
|
||||||
|
}
|
||||||
TEST_P(ParserImplReservedKeywordTest, ModuleVar) {
|
TEST_P(ParserImplReservedKeywordTest, ModuleVar) {
|
||||||
auto name = GetParam();
|
auto name = GetParam();
|
||||||
auto p = parser("var " + name + " : i32 = 1;");
|
auto p = parser("var " + name + " : i32 = 1;");
|
||||||
|
|
|
@ -491,10 +491,7 @@ struct DependencyAnalysis {
|
||||||
[&](const ast::Struct*) { return "struct"; }, //
|
[&](const ast::Struct*) { return "struct"; }, //
|
||||||
[&](const ast::Alias*) { return "alias"; }, //
|
[&](const ast::Alias*) { return "alias"; }, //
|
||||||
[&](const ast::Function*) { return "function"; }, //
|
[&](const ast::Function*) { return "function"; }, //
|
||||||
[&](const ast::Var*) { return "var"; }, //
|
[&](const ast::Variable* v) { return v->Kind(); }, //
|
||||||
[&](const ast::Let*) { return "let"; }, //
|
|
||||||
[&](const ast::Override*) { return "override"; }, //
|
|
||||||
[&](const ast::Const*) { return "const"; }, //
|
|
||||||
[&](Default) {
|
[&](Default) {
|
||||||
UnhandledNode(diagnostics_, node);
|
UnhandledNode(diagnostics_, node);
|
||||||
return "<error>";
|
return "<error>";
|
||||||
|
|
|
@ -327,16 +327,10 @@ bool Validator::VariableConstructorOrCast(const ast::Variable* v,
|
||||||
|
|
||||||
// Value type has to match storage type
|
// Value type has to match storage type
|
||||||
if (storage_ty != value_type) {
|
if (storage_ty != value_type) {
|
||||||
std::string decl = Switch(
|
std::stringstream s;
|
||||||
v, //
|
s << "cannot initialize " << v->Kind() << " of type '" << sem_.TypeNameOf(storage_ty)
|
||||||
[&](const ast::Var*) { return "var"; }, //
|
<< "' with value of type '" << sem_.TypeNameOf(rhs_ty) << "'";
|
||||||
[&](const ast::Let*) { return "let"; }, //
|
AddError(s.str(), v->source);
|
||||||
[&](const ast::Const*) { return "const"; }, //
|
|
||||||
[&](Default) { return "<unknown>"; });
|
|
||||||
|
|
||||||
AddError("cannot initialize " + decl + " of type '" + sem_.TypeNameOf(storage_ty) +
|
|
||||||
"' with value of type '" + sem_.TypeNameOf(rhs_ty) + "'",
|
|
||||||
v->source);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,11 @@
|
||||||
#include "gmock/gmock.h"
|
#include "gmock/gmock.h"
|
||||||
#include "src/tint/program.h"
|
#include "src/tint/program.h"
|
||||||
|
|
||||||
|
// TODO(crbug.com/tint/1580): Remove when 'const' is fully implemented.
|
||||||
|
#if TINT_BUILD_WGSL_READER
|
||||||
|
#include "src/tint/reader/wgsl/parser_impl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if TINT_BUILD_SPV_READER
|
#if TINT_BUILD_SPV_READER
|
||||||
#include "src/tint/reader/spirv/parser_impl_test_helper.h"
|
#include "src/tint/reader/spirv/parser_impl_test_helper.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -54,6 +59,11 @@ struct Flags {
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
testing::InitGoogleMock(&argc, argv);
|
testing::InitGoogleMock(&argc, argv);
|
||||||
|
|
||||||
|
// TODO(crbug.com/tint/1580): Remove when 'const' is fully implemented.
|
||||||
|
#if TINT_BUILD_WGSL_READER
|
||||||
|
tint::reader::wgsl::ParserImpl::EnableConst();
|
||||||
|
#endif
|
||||||
|
|
||||||
#if TINT_BUILD_WGSL_WRITER
|
#if TINT_BUILD_WGSL_WRITER
|
||||||
tint::Program::printer = [](const tint::Program* program) {
|
tint::Program::printer = [](const tint::Program* program) {
|
||||||
auto result = tint::writer::wgsl::Generate(program, {});
|
auto result = tint::writer::wgsl::Generate(program, {});
|
||||||
|
|
Loading…
Reference in New Issue