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>
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index 99e5de9..20c2a97 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -2843,48 +2843,51 @@
// | 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() {
diff --git a/src/reader/wgsl/parser_impl_const_expr_test.cc b/src/reader/wgsl/parser_impl_const_expr_test.cc
index db05cf9..3f313ab 100644
--- a/src/reader/wgsl/parser_impl_const_expr_test.cc
+++ b/src/reader/wgsl/parser_impl_const_expr_test.cc
@@ -112,7 +112,7 @@
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 @@
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) {
diff --git a/src/reader/wgsl/parser_impl_error_msg_test.cc b/src/reader/wgsl/parser_impl_error_msg_test.cc
index 83013a2..86ae4ff 100644
--- a/src/reader/wgsl/parser_impl_error_msg_test.cc
+++ b/src/reader/wgsl/parser_impl_error_msg_test.cc
@@ -434,7 +434,7 @@
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, 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;
diff --git a/src/reader/wgsl/parser_impl_global_constant_decl_test.cc b/src/reader/wgsl/parser_impl_global_constant_decl_test.cc
index bf48641..df4bf98 100644
--- a/src/reader/wgsl/parser_impl_global_constant_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_global_constant_decl_test.cc
@@ -98,7 +98,7 @@
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 @@
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) {
diff --git a/src/reader/wgsl/parser_impl_global_variable_decl_test.cc b/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
index cd89cf4..ba6b115 100644
--- a/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
@@ -152,7 +152,7 @@
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) {
diff --git a/src/reader/wgsl/token.h b/src/reader/wgsl/token.h
index 467e6ac..a8cd213 100644
--- a/src/reader/wgsl/token.h
+++ b/src/reader/wgsl/token.h
@@ -372,7 +372,12 @@
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 ||