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 // | const_literal
Expect<ast::ConstructorExpression*> ParserImpl::expect_const_expr() { Expect<ast::ConstructorExpression*> ParserImpl::expect_const_expr() {
auto t = peek(); auto t = peek();
auto source = t.source(); auto source = t.source();
if (t.IsLiteral()) {
auto type = type_decl(); auto lit = const_literal();
if (type.errored) if (lit.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)
return Failure::kErrored; return Failure::kErrored;
if (!lit.matched)
return add_error(peek(), "unable to parse constant literal");
return create<ast::TypeConstructorExpression>(source, type.value, return create<ast::ScalarConstructorExpression>(source, lit.value);
params.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);
}
} }
return add_error(peek(), "unable to parse const_expr");
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);
} }
Maybe<ast::DecorationList> ParserImpl::decoration_list() { Maybe<ast::DecorationList> ParserImpl::decoration_list() {

View File

@ -112,7 +112,7 @@ TEST_F(ParserImplTest, ConstExpr_InvalidExpr) {
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_TRUE(e.errored); ASSERT_TRUE(e.errored);
ASSERT_EQ(e.value, nullptr); 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) { TEST_F(ParserImplTest, ConstExpr_ConstLiteral) {
@ -134,7 +134,29 @@ TEST_F(ParserImplTest, ConstExpr_ConstLiteral_Invalid) {
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_TRUE(e.errored); ASSERT_TRUE(e.errored);
ASSERT_EQ(e.value, nullptr); 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) { TEST_F(ParserImplTest, ConstExpr_Recursion) {

View File

@ -434,7 +434,7 @@ TEST_F(ParserImplErrorTest, FunctionMissingOpenLine) {
var a : f32 = bar[0]; var a : f32 = bar[0];
return; 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" " var a : f32 = bar[0];\n"
" ^^^\n" " ^^^\n"
"\n" "\n"
@ -473,11 +473,43 @@ TEST_F(ParserImplErrorTest, GlobalDeclConstMissingRParen) {
TEST_F(ParserImplErrorTest, GlobalDeclConstBadConstLiteral) { TEST_F(ParserImplErrorTest, GlobalDeclConstBadConstLiteral) {
EXPECT("let i : vec2<i32> = vec2<i32>(!);", 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" "let i : vec2<i32> = vec2<i32>(!);\n"
" ^\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) { TEST_F(ParserImplErrorTest, GlobalDeclConstExprMaxDepth) {
uint32_t kMaxDepth = 128; uint32_t kMaxDepth = 128;

View File

@ -98,7 +98,7 @@ TEST_F(ParserImplTest, GlobalConstantDecl_InvalidExpression) {
EXPECT_TRUE(e.errored); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched); EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr); 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) { TEST_F(ParserImplTest, GlobalConstantDecl_MissingExpression) {
@ -111,7 +111,7 @@ TEST_F(ParserImplTest, GlobalConstantDecl_MissingExpression) {
EXPECT_TRUE(e.errored); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched); EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr); 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) { TEST_F(ParserImplTest, GlobalConstantDec_Override_WithId) {

View File

@ -152,7 +152,7 @@ TEST_F(ParserImplTest, GlobalVariableDecl_InvalidConstExpr) {
EXPECT_TRUE(e.errored); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched); EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr); 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) { TEST_F(ParserImplTest, GlobalVariableDecl_InvalidVariableDecl) {

View File

@ -372,7 +372,12 @@ class Token {
bool IsEof() const { return type_ == Type::kEOF; } bool IsEof() const { return type_ == Type::kEOF; }
/// @returns true if the token is an identifier /// @returns true if the token is an identifier
bool IsIdentifier() const { return type_ == Type::kIdentifier; } 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' /// @returns true if token is a 'matNxM'
bool IsMatrix() const { bool IsMatrix() const {
return type_ == Type::kMat2x2 || type_ == Type::kMat2x3 || return type_ == Type::kMat2x2 || type_ == Type::kMat2x3 ||