parser: fix wgsl expect_const_expr()

Bug: tint:1025
Change-Id: I35aab866ffce57681662f59e4b8e701bb03cf718
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/59220
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Sarah Mashayekhi <sarahmashay@google.com>
This commit is contained in:
Sarah 2021-07-23 13:15:10 +00:00 committed by Sarah Mashayekhi
parent f7e73d4ee3
commit f76c227cee
6 changed files with 108 additions and 46 deletions

View File

@ -2843,48 +2843,51 @@ Maybe<ast::Literal*> ParserImpl::const_literal() {
// | const_literal
Expect<ast::ConstructorExpression*> ParserImpl::expect_const_expr() {
auto t = peek();
auto source = t.source();
auto type = type_decl();
if (type.errored)
return Failure::kErrored;
if (type.matched) {
auto params = expect_paren_block(
"type constructor", [&]() -> Expect<ast::ExpressionList> {
ast::ExpressionList list;
while (continue_parsing()) {
if (peek_is(Token::Type::kParenRight)) {
break;
}
auto arg = expect_const_expr();
if (arg.errored) {
return Failure::kErrored;
}
list.emplace_back(arg.value);
if (!match(Token::Type::kComma)) {
break;
}
}
return list;
});
if (params.errored)
if (t.IsLiteral()) {
auto lit = const_literal();
if (lit.errored)
return Failure::kErrored;
if (!lit.matched)
return add_error(peek(), "unable to parse constant literal");
return create<ast::TypeConstructorExpression>(source, type.value,
params.value);
return create<ast::ScalarConstructorExpression>(source, lit.value);
} else if (!t.IsIdentifier() || get_type(t.to_str())) {
if (peek_is(Token::Type::kParenLeft, 1) ||
peek_is(Token::Type::kLessThan, 1)) {
auto type = expect_type("const_expr");
if (type.errored)
return Failure::kErrored;
auto params = expect_paren_block(
"type constructor", [&]() -> Expect<ast::ExpressionList> {
ast::ExpressionList list;
while (continue_parsing()) {
if (peek_is(Token::Type::kParenRight)) {
break;
}
auto arg = expect_const_expr();
if (arg.errored) {
return Failure::kErrored;
}
list.emplace_back(arg.value);
if (!match(Token::Type::kComma)) {
break;
}
}
return list;
});
if (params.errored)
return Failure::kErrored;
return create<ast::TypeConstructorExpression>(source, type.value,
params.value);
}
}
auto lit = const_literal();
if (lit.errored)
return Failure::kErrored;
if (!lit.matched)
return add_error(peek(), "unable to parse constant literal");
return create<ast::ScalarConstructorExpression>(source, lit.value);
return add_error(peek(), "unable to parse const_expr");
}
Maybe<ast::DecorationList> ParserImpl::decoration_list() {

View File

@ -112,7 +112,7 @@ TEST_F(ParserImplTest, ConstExpr_InvalidExpr) {
ASSERT_TRUE(p->has_error());
ASSERT_TRUE(e.errored);
ASSERT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:15: unable to parse constant literal");
EXPECT_EQ(p->error(), "1:15: invalid type for const_expr");
}
TEST_F(ParserImplTest, ConstExpr_ConstLiteral) {
@ -134,7 +134,29 @@ TEST_F(ParserImplTest, ConstExpr_ConstLiteral_Invalid) {
ASSERT_TRUE(p->has_error());
ASSERT_TRUE(e.errored);
ASSERT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:1: unknown type 'invalid'");
EXPECT_EQ(p->error(), "1:1: unable to parse const_expr");
}
TEST_F(ParserImplTest, ConstExpr_RegisteredType) {
auto p = parser("S(0)");
auto* mem = Member("m", ty.i32(), ast::DecorationList{});
auto* s = Structure(Sym("S"), {mem});
p->register_type("S", s);
auto e = p->expect_const_expr();
ASSERT_FALSE(e.errored);
ASSERT_TRUE(e->Is<ast::ConstructorExpression>());
ASSERT_TRUE(e->Is<ast::TypeConstructorExpression>());
}
TEST_F(ParserImplTest, ConstExpr_NotRegisteredType) {
auto p = parser("S(0)");
auto e = p->expect_const_expr();
ASSERT_TRUE(p->has_error());
ASSERT_TRUE(e.errored);
ASSERT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:1: unable to parse const_expr");
}
TEST_F(ParserImplTest, ConstExpr_Recursion) {

View File

@ -434,7 +434,7 @@ TEST_F(ParserImplErrorTest, FunctionMissingOpenLine) {
var a : f32 = bar[0];
return;
})",
"test.wgsl:2:17 error: unknown type 'bar'\n"
"test.wgsl:2:17 error: unable to parse const_expr\n"
" var a : f32 = bar[0];\n"
" ^^^\n"
"\n"
@ -473,11 +473,43 @@ TEST_F(ParserImplErrorTest, GlobalDeclConstMissingRParen) {
TEST_F(ParserImplErrorTest, GlobalDeclConstBadConstLiteral) {
EXPECT("let i : vec2<i32> = vec2<i32>(!);",
"test.wgsl:1:31 error: unable to parse constant literal\n"
"test.wgsl:1:31 error: unable to parse const_expr\n"
"let i : vec2<i32> = vec2<i32>(!);\n"
" ^\n");
}
TEST_F(ParserImplErrorTest, GlobalDeclConstBadConstLiteralSpaceLessThan) {
EXPECT("let i = 1 < 2;",
"test.wgsl:1:11 error: expected \';\' for let declaration\n"
"let i = 1 < 2;\n"
" ^\n");
}
TEST_F(ParserImplErrorTest, GlobalDeclConstNotConstExpr) {
EXPECT(
"let a = 1;\n"
"let b = a;",
"test.wgsl:2:9 error: unable to parse const_expr\n"
"let b = a;\n"
" ^\n");
}
TEST_F(ParserImplErrorTest, GlobalDeclConstNotConstExprWithParn) {
EXPECT(
"let a = 1;\n"
"let b = a();",
"test.wgsl:2:9 error: unable to parse const_expr\n"
"let b = a();\n"
" ^\n");
}
TEST_F(ParserImplErrorTest, GlobalDeclConstConstExprRegisteredType) {
EXPECT("let a = S0(0);",
"test.wgsl:1:9 error: unable to parse const_expr\n"
"let a = S0(0);\n"
" ^^\n");
}
TEST_F(ParserImplErrorTest, GlobalDeclConstExprMaxDepth) {
uint32_t kMaxDepth = 128;

View File

@ -98,7 +98,7 @@ TEST_F(ParserImplTest, GlobalConstantDecl_InvalidExpression) {
EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:15: unable to parse constant literal");
EXPECT_EQ(p->error(), "1:15: invalid type for const_expr");
}
TEST_F(ParserImplTest, GlobalConstantDecl_MissingExpression) {
@ -111,7 +111,7 @@ TEST_F(ParserImplTest, GlobalConstantDecl_MissingExpression) {
EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:14: unable to parse constant literal");
EXPECT_EQ(p->error(), "1:14: unable to parse const_expr");
}
TEST_F(ParserImplTest, GlobalConstantDec_Override_WithId) {

View File

@ -152,7 +152,7 @@ TEST_F(ParserImplTest, GlobalVariableDecl_InvalidConstExpr) {
EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:24: unable to parse constant literal");
EXPECT_EQ(p->error(), "1:24: invalid type for const_expr");
}
TEST_F(ParserImplTest, GlobalVariableDecl_InvalidVariableDecl) {

View File

@ -372,7 +372,12 @@ class Token {
bool IsEof() const { return type_ == Type::kEOF; }
/// @returns true if the token is an identifier
bool IsIdentifier() const { return type_ == Type::kIdentifier; }
/// @returns true if the token is a literal
bool IsLiteral() const {
return type_ == Type::kSintLiteral || type_ == Type::kFalse ||
type_ == Type::kUintLiteral || type_ == Type::kTrue ||
type_ == Type::kFloatLiteral;
}
/// @returns true if token is a 'matNxM'
bool IsMatrix() const {
return type_ == Type::kMat2x2 || type_ == Type::kMat2x3 ||