reader/wgsl: Allow trailing commas in lists
Also allows empty constexpr type constructors. Fixed: tint:739 Change-Id: Ic4729c13b6ac538491d5d1d3c7960e78fac80127 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/49443 Commit-Queue: James Price <jrprice@google.com> Auto-Submit: James Price <jrprice@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Ben Clayton <bclayton@google.com>
This commit is contained in:
parent
4248a46bfb
commit
3189bf02e6
|
@ -1416,16 +1416,16 @@ Maybe<ParserImpl::FunctionHeader> ParserImpl::function_header() {
|
|||
|
||||
// param_list
|
||||
// :
|
||||
// | (param COMMA)* param
|
||||
// | (param COMMA)* param COMMA?
|
||||
Expect<ast::VariableList> ParserImpl::expect_param_list() {
|
||||
// Check for an empty list.
|
||||
auto t = peek();
|
||||
if (!t.IsIdentifier() && !t.IsAttrLeft()) {
|
||||
return ast::VariableList{};
|
||||
}
|
||||
|
||||
ast::VariableList ret;
|
||||
while (synchronized_) {
|
||||
// Check for the end of the list.
|
||||
auto t = peek();
|
||||
if (!t.IsIdentifier() && !t.IsAttrLeft()) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto param = expect_param();
|
||||
if (param.errored)
|
||||
return Failure::kErrored;
|
||||
|
@ -1912,34 +1912,26 @@ Maybe<ast::CaseStatement*> ParserImpl::switch_body() {
|
|||
}
|
||||
|
||||
// case_selectors
|
||||
// : const_literal (COMMA const_literal)*
|
||||
// : const_literal (COMMA const_literal)* COMMA?
|
||||
Expect<ast::CaseSelectorList> ParserImpl::expect_case_selectors() {
|
||||
ast::CaseSelectorList selectors;
|
||||
|
||||
for (;;) {
|
||||
auto t = peek();
|
||||
auto matched_comma = match(Token::Type::kComma);
|
||||
|
||||
if (selectors.empty() && matched_comma)
|
||||
return add_error(t, "a selector is expected before the comma");
|
||||
if (matched_comma)
|
||||
t = peek();
|
||||
|
||||
while (synchronized_) {
|
||||
auto cond = const_literal();
|
||||
if (cond.errored)
|
||||
if (cond.errored) {
|
||||
return Failure::kErrored;
|
||||
if (!cond.matched) {
|
||||
if (matched_comma) {
|
||||
return add_error(t, "a selector is expected after the comma");
|
||||
}
|
||||
} else if (!cond.matched) {
|
||||
break;
|
||||
} else if (!cond->Is<ast::IntLiteral>()) {
|
||||
return add_error(cond.value->source(),
|
||||
"invalid case selector must be an integer value");
|
||||
}
|
||||
if (!cond->Is<ast::IntLiteral>())
|
||||
return add_error(t, "invalid case selector must be an integer value");
|
||||
if (!selectors.empty() && !matched_comma)
|
||||
return add_error(t, "expected a comma after the previous selector");
|
||||
|
||||
selectors.push_back(cond.value->As<ast::IntLiteral>());
|
||||
|
||||
if (!match(Token::Type::kComma)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectors.empty())
|
||||
|
@ -2305,25 +2297,18 @@ Maybe<ast::Expression*> ParserImpl::singular_expression() {
|
|||
}
|
||||
|
||||
// argument_expression_list
|
||||
// : PAREN_LEFT (logical_or_expression COMMA)* logical_or_expression
|
||||
// : PAREN_LEFT ((logical_or_expression COMMA)* logical_or_expression COMMA?)?
|
||||
// PAREN_RIGHT
|
||||
Expect<ast::ExpressionList> ParserImpl::expect_argument_expression_list(
|
||||
const std::string& use) {
|
||||
return expect_paren_block(use, [&]() -> Expect<ast::ExpressionList> {
|
||||
// Check for empty list.
|
||||
// TODO(crbug.com/tint/739): Remove this (handled by !arg.matched).
|
||||
if (peek().IsParenRight()) {
|
||||
return ast::ExpressionList{};
|
||||
}
|
||||
|
||||
ast::ExpressionList ret;
|
||||
while (synchronized_) {
|
||||
auto arg = logical_or_expression();
|
||||
if (arg.errored)
|
||||
if (arg.errored) {
|
||||
return Failure::kErrored;
|
||||
if (!arg.matched) {
|
||||
// TODO(crbug.com/tint/739): remove error to allow trailing commas.
|
||||
return add_error(peek(), "unable to parse argument expression");
|
||||
} else if (!arg.matched) {
|
||||
break;
|
||||
}
|
||||
ret.push_back(arg.value);
|
||||
|
||||
|
@ -2838,7 +2823,7 @@ Maybe<ast::Literal*> ParserImpl::const_literal() {
|
|||
}
|
||||
|
||||
// const_expr
|
||||
// : type_decl PAREN_LEFT (const_expr COMMA)? const_expr PAREN_RIGHT
|
||||
// : type_decl PAREN_LEFT ((const_expr COMMA)? const_expr COMMA?)? PAREN_RIGHT
|
||||
// | const_literal
|
||||
Expect<ast::ConstructorExpression*> ParserImpl::expect_const_expr() {
|
||||
auto t = peek();
|
||||
|
@ -2852,15 +2837,20 @@ Expect<ast::ConstructorExpression*> ParserImpl::expect_const_expr() {
|
|||
auto params = expect_paren_block("type constructor",
|
||||
[&]() -> Expect<ast::ExpressionList> {
|
||||
ast::ExpressionList list;
|
||||
auto param = expect_const_expr();
|
||||
if (param.errored)
|
||||
return Failure::kErrored;
|
||||
list.emplace_back(param.value);
|
||||
while (match(Token::Type::kComma)) {
|
||||
param = expect_const_expr();
|
||||
if (param.errored)
|
||||
while (synchronized_) {
|
||||
if (peek().IsParenRight()) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto arg = expect_const_expr();
|
||||
if (arg.errored) {
|
||||
return Failure::kErrored;
|
||||
list.emplace_back(param.value);
|
||||
}
|
||||
list.emplace_back(arg.value);
|
||||
|
||||
if (!match(Token::Type::kComma)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return list;
|
||||
});
|
||||
|
|
|
@ -50,6 +50,17 @@ TEST_F(ParserImplTest, ArgumentExpressionList_ParsesMultiple) {
|
|||
ASSERT_TRUE(e.value[2]->Is<ast::BinaryExpression>());
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, ArgumentExpressionList_TrailingComma) {
|
||||
auto p = parser("(a, 42,)");
|
||||
auto e = p->expect_argument_expression_list("argument list");
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
ASSERT_FALSE(e.errored);
|
||||
|
||||
ASSERT_EQ(e.value.size(), 2u);
|
||||
ASSERT_TRUE(e.value[0]->Is<ast::IdentifierExpression>());
|
||||
ASSERT_TRUE(e.value[1]->Is<ast::ConstructorExpression>());
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, ArgumentExpressionList_HandlesMissingLeftParen) {
|
||||
auto p = parser("a)");
|
||||
auto e = p->expect_argument_expression_list("argument list");
|
||||
|
@ -66,12 +77,20 @@ TEST_F(ParserImplTest, ArgumentExpressionList_HandlesMissingRightParen) {
|
|||
EXPECT_EQ(p->error(), "1:3: expected ')' for argument list");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, ArgumentExpressionList_HandlesMissingExpression) {
|
||||
auto p = parser("(a, )");
|
||||
TEST_F(ParserImplTest, ArgumentExpressionList_HandlesMissingExpression_0) {
|
||||
auto p = parser("(,)");
|
||||
auto e = p->expect_argument_expression_list("argument list");
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_TRUE(e.errored);
|
||||
EXPECT_EQ(p->error(), "1:5: unable to parse argument expression");
|
||||
EXPECT_EQ(p->error(), "1:2: expected ')' for argument list");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, ArgumentExpressionList_HandlesMissingExpression_1) {
|
||||
auto p = parser("(a, ,)");
|
||||
auto e = p->expect_argument_expression_list("argument list");
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_TRUE(e.errored);
|
||||
EXPECT_EQ(p->error(), "1:5: expected ')' for argument list");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, ArgumentExpressionList_HandlesInvalidExpression) {
|
||||
|
@ -79,7 +98,7 @@ TEST_F(ParserImplTest, ArgumentExpressionList_HandlesInvalidExpression) {
|
|||
auto e = p->expect_argument_expression_list("argument list");
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_TRUE(e.errored);
|
||||
EXPECT_EQ(p->error(), "1:2: unable to parse argument expression");
|
||||
EXPECT_EQ(p->error(), "1:2: expected ')' for argument list");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -59,13 +59,33 @@ TEST_F(ParserImplTest, Statement_Call_WithParams) {
|
|||
EXPECT_TRUE(c->params()[2]->Is<ast::BinaryExpression>());
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, Statement_Call_WithParams_TrailingComma) {
|
||||
auto p = parser("a(1, b,);");
|
||||
auto e = p->statement();
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
ASSERT_NE(e.value, nullptr);
|
||||
EXPECT_TRUE(e.matched);
|
||||
EXPECT_FALSE(e.errored);
|
||||
|
||||
ASSERT_TRUE(e->Is<ast::CallStatement>());
|
||||
auto* c = e->As<ast::CallStatement>()->expr();
|
||||
|
||||
ASSERT_TRUE(c->func()->Is<ast::IdentifierExpression>());
|
||||
auto* ident = c->func()->As<ast::IdentifierExpression>();
|
||||
EXPECT_EQ(ident->symbol(), p->builder().Symbols().Get("a"));
|
||||
|
||||
EXPECT_EQ(c->params().size(), 2u);
|
||||
EXPECT_TRUE(c->params()[0]->Is<ast::ConstructorExpression>());
|
||||
EXPECT_TRUE(c->params()[1]->Is<ast::IdentifierExpression>());
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, Statement_Call_Missing_RightParen) {
|
||||
auto p = parser("a(");
|
||||
auto e = p->statement();
|
||||
EXPECT_TRUE(p->has_error());
|
||||
EXPECT_TRUE(e.errored);
|
||||
EXPECT_FALSE(e.matched);
|
||||
EXPECT_EQ(p->error(), "1:3: unable to parse argument expression");
|
||||
EXPECT_EQ(p->error(), "1:3: expected ')' for function call");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, Statement_Call_Missing_Semi) {
|
||||
|
|
|
@ -47,6 +47,38 @@ TEST_F(ParserImplTest, ConstExpr_TypeDecl) {
|
|||
EXPECT_FLOAT_EQ(c->literal()->As<ast::FloatLiteral>()->value(), 2.);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, ConstExpr_TypeDecl_Empty) {
|
||||
auto p = parser("vec2<f32>()");
|
||||
auto e = p->expect_const_expr();
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
ASSERT_FALSE(e.errored);
|
||||
ASSERT_TRUE(e->Is<ast::ConstructorExpression>());
|
||||
ASSERT_TRUE(e->Is<ast::TypeConstructorExpression>());
|
||||
|
||||
auto* t = e->As<ast::TypeConstructorExpression>();
|
||||
ASSERT_TRUE(t->type()->Is<sem::Vector>());
|
||||
EXPECT_EQ(t->type()->As<sem::Vector>()->size(), 2u);
|
||||
|
||||
ASSERT_EQ(t->values().size(), 0u);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, ConstExpr_TypeDecl_TrailingComma) {
|
||||
auto p = parser("vec2<f32>(1., 2.,)");
|
||||
auto e = p->expect_const_expr();
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
ASSERT_FALSE(e.errored);
|
||||
ASSERT_TRUE(e->Is<ast::ConstructorExpression>());
|
||||
ASSERT_TRUE(e->Is<ast::TypeConstructorExpression>());
|
||||
|
||||
auto* t = e->As<ast::TypeConstructorExpression>();
|
||||
ASSERT_TRUE(t->type()->Is<sem::Vector>());
|
||||
EXPECT_EQ(t->type()->As<sem::Vector>()->size(), 2u);
|
||||
|
||||
ASSERT_EQ(t->values().size(), 2u);
|
||||
ASSERT_TRUE(t->values()[0]->Is<ast::ScalarConstructorExpression>());
|
||||
ASSERT_TRUE(t->values()[1]->Is<ast::ScalarConstructorExpression>());
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, ConstExpr_TypeDecl_MissingRightParen) {
|
||||
auto p = parser("vec2<f32>(1., 2.");
|
||||
auto e = p->expect_const_expr();
|
||||
|
@ -65,15 +97,6 @@ TEST_F(ParserImplTest, ConstExpr_TypeDecl_MissingLeftParen) {
|
|||
EXPECT_EQ(p->error(), "1:11: expected '(' for type constructor");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, ConstExpr_TypeDecl_HangingComma) {
|
||||
auto p = parser("vec2<f32>(1.,)");
|
||||
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:14: unable to parse constant literal");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, ConstExpr_TypeDecl_MissingComma) {
|
||||
auto p = parser("vec2<f32>(1. 2.");
|
||||
auto e = p->expect_const_expr();
|
||||
|
@ -83,15 +106,6 @@ TEST_F(ParserImplTest, ConstExpr_TypeDecl_MissingComma) {
|
|||
EXPECT_EQ(p->error(), "1:14: expected ')' for type constructor");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, ConstExpr_MissingExpr) {
|
||||
auto p = parser("vec2<f32>()");
|
||||
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:11: unable to parse constant literal");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, ConstExpr_InvalidExpr) {
|
||||
auto p = parser("vec2<f32>(1., if(a) {})");
|
||||
auto e = p->expect_const_expr();
|
||||
|
|
|
@ -137,14 +137,14 @@ TEST_F(ParserImplErrorTest, CallStmtMissingRParen) {
|
|||
|
||||
TEST_F(ParserImplErrorTest, CallStmtInvalidArgument0) {
|
||||
EXPECT("fn f() { f(<); }",
|
||||
"test.wgsl:1:12 error: unable to parse argument expression\n"
|
||||
"test.wgsl:1:12 error: expected ')' for function call\n"
|
||||
"fn f() { f(<); }\n"
|
||||
" ^\n");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplErrorTest, CallStmtInvalidArgument1) {
|
||||
EXPECT("fn f() { f(1.0, <); }",
|
||||
"test.wgsl:1:17 error: unable to parse argument expression\n"
|
||||
"test.wgsl:1:17 error: expected ')' for function call\n"
|
||||
"fn f() { f(1.0, <); }\n"
|
||||
" ^\n");
|
||||
}
|
||||
|
@ -446,9 +446,9 @@ TEST_F(ParserImplErrorTest, FunctionDeclParamInvalidType) {
|
|||
}
|
||||
|
||||
TEST_F(ParserImplErrorTest, FunctionDeclParamMissing) {
|
||||
EXPECT("fn f(x : i32, ) {}",
|
||||
"test.wgsl:1:15 error: expected identifier for parameter\n"
|
||||
"fn f(x : i32, ) {}\n"
|
||||
EXPECT("fn f(x : i32, ,) {}",
|
||||
"test.wgsl:1:15 error: expected ')' for function declaration\n"
|
||||
"fn f(x : i32, ,) {}\n"
|
||||
" ^\n");
|
||||
}
|
||||
|
||||
|
|
|
@ -250,7 +250,7 @@ TEST_F(ForStmtErrorTest, InvalidBreakConditionMatch) {
|
|||
// Test a for loop with an invalid continuing statement.
|
||||
TEST_F(ForStmtErrorTest, InvalidContinuingAsFuncCall) {
|
||||
std::string for_str = "for (;; a(,) ) { }";
|
||||
std::string error_str = "1:11: unable to parse argument expression";
|
||||
std::string error_str = "1:11: expected ')' for function call";
|
||||
|
||||
TestForWithError(for_str, error_str);
|
||||
}
|
||||
|
|
|
@ -33,6 +33,18 @@ TEST_F(ParserImplTest, FunctionHeader) {
|
|||
EXPECT_TRUE(f->return_type->Is<sem::Void>());
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, FunctionHeader_TrailingComma) {
|
||||
auto p = parser("fn main(a :i32,)");
|
||||
auto f = p->function_header();
|
||||
EXPECT_TRUE(f.matched);
|
||||
EXPECT_FALSE(f.errored);
|
||||
|
||||
EXPECT_EQ(f->name, "main");
|
||||
ASSERT_EQ(f->params.size(), 1u);
|
||||
EXPECT_EQ(f->params[0]->symbol(), p->builder().Symbols().Get("a"));
|
||||
EXPECT_TRUE(f->return_type->Is<sem::Void>());
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, FunctionHeader_DecoratedReturnType) {
|
||||
auto p = parser("fn main() -> [[location(1)]] f32");
|
||||
auto f = p->function_header();
|
||||
|
@ -77,12 +89,12 @@ TEST_F(ParserImplTest, FunctionHeader_MissingParenLeft) {
|
|||
}
|
||||
|
||||
TEST_F(ParserImplTest, FunctionHeader_InvalidParamList) {
|
||||
auto p = parser("fn main(a :i32,) -> i32");
|
||||
auto p = parser("fn main(a :i32, ,) -> i32");
|
||||
auto f = p->function_header();
|
||||
EXPECT_FALSE(f.matched);
|
||||
EXPECT_TRUE(f.errored);
|
||||
EXPECT_TRUE(p->has_error());
|
||||
EXPECT_EQ(p->error(), "1:16: expected identifier for parameter");
|
||||
EXPECT_EQ(p->error(), "1:17: expected ')' for function declaration");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, FunctionHeader_MissingParenRight) {
|
||||
|
|
|
@ -87,12 +87,12 @@ TEST_F(ParserImplTest, ParamList_Empty) {
|
|||
EXPECT_EQ(e.value.size(), 0u);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, ParamList_HangingComma) {
|
||||
TEST_F(ParserImplTest, ParamList_TrailingComma) {
|
||||
auto p = parser("a : i32,");
|
||||
auto e = p->expect_param_list();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_TRUE(e.errored);
|
||||
EXPECT_EQ(p->error(), "1:9: expected identifier for parameter");
|
||||
ASSERT_FALSE(p->has_error());
|
||||
ASSERT_FALSE(e.errored);
|
||||
EXPECT_EQ(e.value.size(), 1u);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, ParamList_Decorations) {
|
||||
|
|
|
@ -121,7 +121,7 @@ TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_InvalidValue) {
|
|||
EXPECT_TRUE(e.errored);
|
||||
EXPECT_EQ(e.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
EXPECT_EQ(p->error(), "1:5: unable to parse argument expression");
|
||||
EXPECT_EQ(p->error(), "1:5: expected ')' for type constructor");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_StructConstructor_Empty) {
|
||||
|
|
|
@ -128,6 +128,18 @@ TEST_F(ParserImplTest, SingularExpression_Call_WithArgs) {
|
|||
EXPECT_TRUE(c->params()[2]->Is<ast::BinaryExpression>());
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, SingularExpression_Call_TrailingComma) {
|
||||
auto p = parser("a(b, )");
|
||||
auto e = p->singular_expression();
|
||||
EXPECT_TRUE(e.matched);
|
||||
EXPECT_FALSE(e.errored);
|
||||
ASSERT_NE(e.value, nullptr);
|
||||
|
||||
ASSERT_TRUE(e->Is<ast::CallExpression>());
|
||||
auto* c = e->As<ast::CallExpression>();
|
||||
EXPECT_EQ(c->params().size(), 1u);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, SingularExpression_Call_InvalidArg) {
|
||||
auto p = parser("a(if(a) {})");
|
||||
auto e = p->singular_expression();
|
||||
|
@ -135,17 +147,7 @@ TEST_F(ParserImplTest, SingularExpression_Call_InvalidArg) {
|
|||
EXPECT_TRUE(e.errored);
|
||||
EXPECT_EQ(e.value, nullptr);
|
||||
EXPECT_TRUE(p->has_error());
|
||||
EXPECT_EQ(p->error(), "1:3: unable to parse argument expression");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, SingularExpression_Call_HangingComma) {
|
||||
auto p = parser("a(b, )");
|
||||
auto e = p->singular_expression();
|
||||
EXPECT_FALSE(e.matched);
|
||||
EXPECT_TRUE(e.errored);
|
||||
EXPECT_EQ(e.value, nullptr);
|
||||
EXPECT_TRUE(p->has_error());
|
||||
EXPECT_EQ(p->error(), "1:6: unable to parse argument expression");
|
||||
EXPECT_EQ(p->error(), "1:3: expected ')' for function call");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, SingularExpression_Call_MissingRightParen) {
|
||||
|
@ -155,7 +157,7 @@ TEST_F(ParserImplTest, SingularExpression_Call_MissingRightParen) {
|
|||
EXPECT_TRUE(e.errored);
|
||||
EXPECT_EQ(e.value, nullptr);
|
||||
EXPECT_TRUE(p->has_error());
|
||||
EXPECT_EQ(p->error(), "1:3: unable to parse argument expression");
|
||||
EXPECT_EQ(p->error(), "1:3: expected ')' for function call");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, SingularExpression_MemberAccessor) {
|
||||
|
|
|
@ -28,10 +28,28 @@ TEST_F(ParserImplTest, SwitchBody_Case) {
|
|||
ASSERT_NE(e.value, nullptr);
|
||||
ASSERT_TRUE(e->Is<ast::CaseStatement>());
|
||||
EXPECT_FALSE(e->IsDefault());
|
||||
auto* stmt = e->As<ast::CaseStatement>();
|
||||
ASSERT_EQ(stmt->selectors().size(), 1u);
|
||||
EXPECT_EQ(stmt->selectors()[0]->value_as_u32(), 1u);
|
||||
ASSERT_EQ(e->body()->size(), 1u);
|
||||
EXPECT_TRUE(e->body()->get(0)->Is<ast::AssignmentStatement>());
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, SwitchBody_Case_TrailingComma) {
|
||||
auto p = parser("case 1, 2,: { }");
|
||||
auto e = p->switch_body();
|
||||
EXPECT_FALSE(p->has_error()) << p->error();
|
||||
EXPECT_TRUE(e.matched);
|
||||
EXPECT_FALSE(e.errored);
|
||||
ASSERT_NE(e.value, nullptr);
|
||||
ASSERT_TRUE(e->Is<ast::CaseStatement>());
|
||||
EXPECT_FALSE(e->IsDefault());
|
||||
auto* stmt = e->As<ast::CaseStatement>();
|
||||
ASSERT_EQ(stmt->selectors().size(), 2u);
|
||||
EXPECT_EQ(stmt->selectors()[0]->value_as_u32(), 1u);
|
||||
EXPECT_EQ(stmt->selectors()[1]->value_as_u32(), 2u);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, SwitchBody_Case_InvalidConstLiteral) {
|
||||
auto p = parser("case a == 4: { a = 4; }");
|
||||
auto e = p->switch_body();
|
||||
|
@ -134,17 +152,7 @@ TEST_F(ParserImplTest, SwitchBody_Case_MultipleSelectorsMissingComma) {
|
|||
EXPECT_TRUE(e.errored);
|
||||
EXPECT_FALSE(e.matched);
|
||||
EXPECT_EQ(e.value, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:8: expected a comma after the previous selector");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, SwitchBody_Case_MultipleSelectorsEndsWithComma) {
|
||||
auto p = parser("case 1, 2,: { }");
|
||||
auto e = p->switch_body();
|
||||
EXPECT_TRUE(p->has_error());
|
||||
EXPECT_TRUE(e.errored);
|
||||
EXPECT_FALSE(e.matched);
|
||||
EXPECT_EQ(e.value, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:11: a selector is expected after the comma");
|
||||
EXPECT_EQ(p->error(), "1:8: expected ':' for case statement");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, SwitchBody_Case_MultipleSelectorsStartsWithComma) {
|
||||
|
@ -154,7 +162,7 @@ TEST_F(ParserImplTest, SwitchBody_Case_MultipleSelectorsStartsWithComma) {
|
|||
EXPECT_TRUE(e.errored);
|
||||
EXPECT_FALSE(e.matched);
|
||||
EXPECT_EQ(e.value, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:6: a selector is expected before the comma");
|
||||
EXPECT_EQ(p->error(), "1:6: unable to parse case selectors");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, SwitchBody_Default) {
|
||||
|
|
Loading…
Reference in New Issue