wsgl parser: Add expect_block(), use it
`expect_block()` takes a start and end token, along with a function to parse a lexical block body. This reduces code, keeps error messages consistent, and also gives us a future place to try resynchronising the parser so we can have more than one error emitted. `expect_paren_block()` and `expect_brace_block()` are convenience helpers for providing the start and end tokens for common block types. Bug: tint:282 Change-Id: I432a0301727b131a6fce875687b952dfc6889a4b Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/31736 Commit-Queue: Ben Clayton <bclayton@google.com> Reviewed-by: dan sinclair <dsinclair@chromium.org>
This commit is contained in:
parent
b8791a5129
commit
786bc92002
|
@ -435,62 +435,38 @@ std::unique_ptr<ast::VariableDecoration> ParserImpl::variable_decoration() {
|
|||
Source source;
|
||||
if (match(Token::Type::kLocation, &source)) {
|
||||
const char* use = "location decoration";
|
||||
|
||||
if (!expect(use, Token::Type::kParenLeft))
|
||||
return nullptr;
|
||||
|
||||
uint32_t val;
|
||||
if (!expect_positive_sint(use, &val))
|
||||
return nullptr;
|
||||
|
||||
if (!expect(use, Token::Type::kParenRight))
|
||||
return nullptr;
|
||||
|
||||
return std::make_unique<ast::LocationDecoration>(val, source);
|
||||
return expect_paren_block(use, [&] {
|
||||
uint32_t val;
|
||||
bool ok = expect_positive_sint(use, &val);
|
||||
return ok ? std::make_unique<ast::LocationDecoration>(val, source)
|
||||
: nullptr;
|
||||
});
|
||||
}
|
||||
if (match(Token::Type::kBuiltin, &source)) {
|
||||
if (!expect("builtin decoration", Token::Type::kParenLeft))
|
||||
return nullptr;
|
||||
|
||||
ast::Builtin builtin;
|
||||
std::tie(builtin, source) = expect_builtin();
|
||||
if (builtin == ast::Builtin::kNone)
|
||||
return nullptr;
|
||||
|
||||
if (!expect("builtin decoration", Token::Type::kParenRight))
|
||||
return nullptr;
|
||||
|
||||
return std::make_unique<ast::BuiltinDecoration>(builtin, source);
|
||||
return expect_paren_block("builtin decoration", [&] {
|
||||
ast::Builtin builtin;
|
||||
std::tie(builtin, source) = expect_builtin();
|
||||
return (builtin != ast::Builtin::kNone)
|
||||
? std::make_unique<ast::BuiltinDecoration>(builtin, source)
|
||||
: nullptr;
|
||||
});
|
||||
}
|
||||
if (match(Token::Type::kBinding, &source)) {
|
||||
const char* use = "binding decoration";
|
||||
|
||||
if (!expect(use, Token::Type::kParenLeft))
|
||||
return nullptr;
|
||||
|
||||
uint32_t val;
|
||||
if (!expect_positive_sint(use, &val))
|
||||
return nullptr;
|
||||
|
||||
if (!expect(use, Token::Type::kParenRight))
|
||||
return nullptr;
|
||||
|
||||
return std::make_unique<ast::BindingDecoration>(val, source);
|
||||
return expect_paren_block(use, [&] {
|
||||
uint32_t val;
|
||||
bool ok = expect_positive_sint(use, &val);
|
||||
return ok ? std::make_unique<ast::BindingDecoration>(val, source)
|
||||
: nullptr;
|
||||
});
|
||||
}
|
||||
if (match(Token::Type::kSet, &source)) {
|
||||
const char* use = "set decoration";
|
||||
|
||||
if (!expect(use, Token::Type::kParenLeft))
|
||||
return nullptr;
|
||||
|
||||
uint32_t val;
|
||||
if (!expect_positive_sint(use, &val))
|
||||
return nullptr;
|
||||
|
||||
if (!expect(use, Token::Type::kParenRight))
|
||||
return nullptr;
|
||||
|
||||
return std::make_unique<ast::SetDecoration>(val, source);
|
||||
return expect_paren_block(use, [&] {
|
||||
uint32_t val;
|
||||
bool ok = expect_positive_sint(use, &val);
|
||||
return ok ? std::make_unique<ast::SetDecoration>(val, source) : nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
@ -1200,25 +1176,24 @@ bool ParserImpl::array_decoration_list(ast::ArrayDecorationList& decos) {
|
|||
|
||||
for (;;) {
|
||||
Source source;
|
||||
if (!match(Token::Type::kStride, &source)) {
|
||||
if (match(Token::Type::kStride, &source)) {
|
||||
const char* use = "stride decoration";
|
||||
auto deco = expect_paren_block(use, [&] {
|
||||
uint32_t val;
|
||||
bool ok = expect_nonzero_positive_sint(use, &val);
|
||||
return ok ? std::make_unique<ast::StrideDecoration>(val, source)
|
||||
: nullptr;
|
||||
});
|
||||
|
||||
if (!deco)
|
||||
return false;
|
||||
|
||||
decos.emplace_back(std::move(deco));
|
||||
} else {
|
||||
add_error(source, "unknown array decoration");
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* use = "stride decoration";
|
||||
|
||||
if (!expect(use, Token::Type::kParenLeft))
|
||||
return false;
|
||||
|
||||
uint32_t stride;
|
||||
if (!expect_nonzero_positive_sint(use, &stride))
|
||||
return false;
|
||||
|
||||
decos.push_back(std::make_unique<ast::StrideDecoration>(stride, source));
|
||||
|
||||
if (!expect(use, Token::Type::kParenRight))
|
||||
return false;
|
||||
|
||||
if (!match(Token::Type::kComma))
|
||||
break;
|
||||
}
|
||||
|
@ -1402,43 +1377,23 @@ std::unique_ptr<ast::StructDecoration> ParserImpl::struct_decoration(Token t) {
|
|||
// struct_body_decl
|
||||
// : BRACKET_LEFT struct_member* BRACKET_RIGHT
|
||||
ast::StructMemberList ParserImpl::struct_body_decl() {
|
||||
auto t = peek();
|
||||
if (!t.IsBraceLeft()) {
|
||||
add_error(t, "missing { for struct declaration");
|
||||
return {};
|
||||
}
|
||||
next(); // Consume the peek
|
||||
return expect_brace_block("struct declaration", [&] {
|
||||
ast::StructMemberList members;
|
||||
|
||||
t = peek();
|
||||
if (t.IsBraceRight()) {
|
||||
next(); // Consume the peek
|
||||
return {};
|
||||
}
|
||||
while (!peek().IsBraceRight() && !peek().IsEof()) {
|
||||
auto mem = struct_member();
|
||||
if (has_error())
|
||||
return ast::StructMemberList{};
|
||||
if (mem == nullptr) {
|
||||
add_error(peek(), "invalid struct member");
|
||||
return ast::StructMemberList{};
|
||||
}
|
||||
|
||||
ast::StructMemberList members;
|
||||
for (;;) {
|
||||
auto mem = struct_member();
|
||||
if (has_error())
|
||||
return {};
|
||||
if (mem == nullptr) {
|
||||
add_error(peek(), "invalid struct member");
|
||||
return {};
|
||||
members.push_back(std::move(mem));
|
||||
}
|
||||
|
||||
members.push_back(std::move(mem));
|
||||
|
||||
t = peek();
|
||||
if (t.IsBraceRight() || t.IsEof())
|
||||
break;
|
||||
}
|
||||
|
||||
t = next();
|
||||
if (!t.IsBraceRight()) {
|
||||
add_error(t, "missing } for struct declaration");
|
||||
return {};
|
||||
}
|
||||
|
||||
return members;
|
||||
return members;
|
||||
});
|
||||
}
|
||||
|
||||
// struct_member
|
||||
|
@ -1519,18 +1474,12 @@ ParserImpl::struct_member_decoration() {
|
|||
return nullptr;
|
||||
|
||||
const char* use = "offset decoration";
|
||||
|
||||
if (!expect(use, Token::Type::kParenLeft))
|
||||
return nullptr;
|
||||
|
||||
uint32_t val;
|
||||
if (!expect_positive_sint(use, &val))
|
||||
return nullptr;
|
||||
|
||||
if (!expect(use, Token::Type::kParenRight))
|
||||
return nullptr;
|
||||
|
||||
return std::make_unique<ast::StructMemberOffsetDecoration>(val, source);
|
||||
return expect_paren_block(use, [&] {
|
||||
uint32_t val;
|
||||
bool ok = expect_positive_sint(use, &val);
|
||||
return ok ? std::make_unique<ast::StructMemberOffsetDecoration>(val, source)
|
||||
: nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
// function_decl
|
||||
|
@ -1624,55 +1573,36 @@ bool ParserImpl::function_decoration_decl(ast::FunctionDecorationList& decos) {
|
|||
// | WORKGROUP_SIZE PAREN_LEFT INT_LITERAL
|
||||
// (COMMA INT_LITERAL (COMMA INT_LITERAL)?)? PAREN_RIGHT
|
||||
std::unique_ptr<ast::FunctionDecoration> ParserImpl::function_decoration() {
|
||||
auto t = peek();
|
||||
auto source = t.source();
|
||||
if (t.IsWorkgroupSize()) {
|
||||
next(); // Consume the peek
|
||||
|
||||
const char* use = "workgroup_size decoration";
|
||||
|
||||
if (!expect(use, Token::Type::kParenLeft))
|
||||
return nullptr;
|
||||
|
||||
uint32_t x;
|
||||
if (!expect_nonzero_positive_sint("workgroup_size x parameter", &x)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t y = 1;
|
||||
uint32_t z = 1;
|
||||
if (match(Token::Type::kComma)) {
|
||||
if (!expect_nonzero_positive_sint("workgroup_size y parameter", &y)) {
|
||||
return nullptr;
|
||||
Source source;
|
||||
if (match(Token::Type::kWorkgroupSize, &source)) {
|
||||
return expect_paren_block("workgroup_size decoration", [&]() {
|
||||
uint32_t x;
|
||||
if (!expect_nonzero_positive_sint("workgroup_size x parameter", &x)) {
|
||||
return std::unique_ptr<ast::WorkgroupDecoration>(nullptr);
|
||||
}
|
||||
uint32_t y = 1;
|
||||
uint32_t z = 1;
|
||||
if (match(Token::Type::kComma)) {
|
||||
if (!expect_nonzero_positive_sint("workgroup_size z parameter", &z)) {
|
||||
return nullptr;
|
||||
if (!expect_nonzero_positive_sint("workgroup_size y parameter", &y)) {
|
||||
return std::unique_ptr<ast::WorkgroupDecoration>(nullptr);
|
||||
}
|
||||
if (match(Token::Type::kComma)) {
|
||||
if (!expect_nonzero_positive_sint("workgroup_size z parameter", &z)) {
|
||||
return std::unique_ptr<ast::WorkgroupDecoration>(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!expect(use, Token::Type::kParenRight))
|
||||
return nullptr;
|
||||
|
||||
return std::make_unique<ast::WorkgroupDecoration>(uint32_t(x), uint32_t(y),
|
||||
uint32_t(z), source);
|
||||
return std::make_unique<ast::WorkgroupDecoration>(x, y, z, source);
|
||||
});
|
||||
}
|
||||
if (t.IsStage()) {
|
||||
next(); // Consume the peek
|
||||
|
||||
if (!expect("stage decoration", Token::Type::kParenLeft))
|
||||
return nullptr;
|
||||
|
||||
ast::PipelineStage stage;
|
||||
std::tie(stage, source) = expect_pipeline_stage();
|
||||
if (stage == ast::PipelineStage::kNone)
|
||||
return nullptr;
|
||||
|
||||
if (!expect("stage decoration", Token::Type::kParenRight))
|
||||
return nullptr;
|
||||
|
||||
return std::make_unique<ast::StageDecoration>(stage, source);
|
||||
if (match(Token::Type::kStage, &source)) {
|
||||
return expect_paren_block("stage decoration", [&]() {
|
||||
ast::PipelineStage stage;
|
||||
std::tie(stage, source) = expect_pipeline_stage();
|
||||
return (stage != ast::PipelineStage::kNone)
|
||||
? std::make_unique<ast::StageDecoration>(stage, source)
|
||||
: nullptr;
|
||||
});
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -1702,16 +1632,11 @@ std::unique_ptr<ast::Function> ParserImpl::function_header() {
|
|||
if (!expect_ident(use, &name))
|
||||
return nullptr;
|
||||
|
||||
if (!expect(use, Token::Type::kParenLeft))
|
||||
return nullptr;
|
||||
auto params = expect_paren_block(use, [&] { return param_list(); });
|
||||
|
||||
auto params = param_list();
|
||||
if (has_error())
|
||||
return nullptr;
|
||||
|
||||
if (!expect(use, Token::Type::kParenRight))
|
||||
return nullptr;
|
||||
|
||||
auto t = next();
|
||||
if (!t.IsArrow()) {
|
||||
add_error(t, "missing -> for function declaration");
|
||||
|
@ -1808,45 +1733,23 @@ std::pair<ast::Builtin, Source> ParserImpl::expect_builtin() {
|
|||
// body_stmt
|
||||
// : BRACKET_LEFT statements BRACKET_RIGHT
|
||||
std::unique_ptr<ast::BlockStatement> ParserImpl::body_stmt() {
|
||||
auto t = peek();
|
||||
if (!t.IsBraceLeft()) {
|
||||
add_error(t, "missing {");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
next(); // Consume the peek
|
||||
|
||||
auto stmts = statements();
|
||||
if (has_error())
|
||||
return nullptr;
|
||||
|
||||
t = next();
|
||||
if (!t.IsBraceRight()) {
|
||||
add_error(t, "missing }");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return stmts;
|
||||
return expect_brace_block("", [&] { return statements(); });
|
||||
}
|
||||
|
||||
// paren_rhs_stmt
|
||||
// : PAREN_LEFT logical_or_expression PAREN_RIGHT
|
||||
std::unique_ptr<ast::Expression> ParserImpl::paren_rhs_stmt() {
|
||||
if (!expect("", Token::Type::kParenLeft))
|
||||
return nullptr;
|
||||
return expect_paren_block("", [&]() -> std::unique_ptr<ast::Expression> {
|
||||
auto expr = logical_or_expression();
|
||||
if (has_error())
|
||||
return nullptr;
|
||||
|
||||
auto expr = logical_or_expression();
|
||||
if (has_error())
|
||||
return nullptr;
|
||||
if (expr == nullptr) {
|
||||
add_error(peek(), "unable to parse expression");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!expect("", Token::Type::kParenRight))
|
||||
return nullptr;
|
||||
|
||||
return expr;
|
||||
if (expr == nullptr) {
|
||||
add_error(peek(), "unable to parse expression");
|
||||
return nullptr;
|
||||
}
|
||||
return expr;
|
||||
});
|
||||
}
|
||||
|
||||
// statements
|
||||
|
@ -2174,28 +2077,23 @@ std::unique_ptr<ast::SwitchStatement> ParserImpl::switch_stmt() {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
auto t = next();
|
||||
if (!t.IsBraceLeft()) {
|
||||
add_error(t, "missing { for switch statement");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ast::CaseStatementList body;
|
||||
for (;;) {
|
||||
auto stmt = switch_body();
|
||||
if (has_error())
|
||||
return nullptr;
|
||||
if (stmt == nullptr)
|
||||
break;
|
||||
bool ok = expect_brace_block("switch statement", [&] {
|
||||
for (;;) {
|
||||
auto stmt = switch_body();
|
||||
if (has_error())
|
||||
return false;
|
||||
if (stmt == nullptr)
|
||||
break;
|
||||
|
||||
body.push_back(std::move(stmt));
|
||||
}
|
||||
body.push_back(std::move(stmt));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
t = next();
|
||||
if (!t.IsBraceRight()) {
|
||||
add_error(t, "missing } for switch statement");
|
||||
if (!ok)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::make_unique<ast::SwitchStatement>(source, std::move(condition),
|
||||
std::move(body));
|
||||
}
|
||||
|
@ -2224,30 +2122,18 @@ std::unique_ptr<ast::CaseStatement> ParserImpl::switch_body() {
|
|||
stmt->set_selectors(std::move(selectors));
|
||||
}
|
||||
|
||||
t = next();
|
||||
if (!t.IsColon()) {
|
||||
add_error(t, "missing : for case statement");
|
||||
return nullptr;
|
||||
}
|
||||
const char* use = "case statement";
|
||||
|
||||
t = next();
|
||||
if (!t.IsBraceLeft()) {
|
||||
add_error(t, "missing { for case statement");
|
||||
if (!expect(use, Token::Type::kColon))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto body = case_body();
|
||||
if (has_error())
|
||||
auto body = expect_brace_block(use, [&] { return case_body(); });
|
||||
|
||||
if (body == nullptr)
|
||||
return nullptr;
|
||||
|
||||
stmt->set_body(std::move(body));
|
||||
|
||||
t = next();
|
||||
if (!t.IsBraceRight()) {
|
||||
add_error(t, "missing } for case statement");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return stmt;
|
||||
}
|
||||
|
||||
|
@ -2313,28 +2199,19 @@ std::unique_ptr<ast::LoopStatement> ParserImpl::loop_stmt() {
|
|||
if (!match(Token::Type::kLoop, &source))
|
||||
return nullptr;
|
||||
|
||||
auto t = next();
|
||||
if (!t.IsBraceLeft()) {
|
||||
add_error(t, "missing { for loop");
|
||||
return nullptr;
|
||||
}
|
||||
return expect_brace_block(
|
||||
"loop", [&]() -> std::unique_ptr<ast::LoopStatement> {
|
||||
auto body = statements();
|
||||
if (has_error())
|
||||
return nullptr;
|
||||
|
||||
auto body = statements();
|
||||
if (has_error())
|
||||
return nullptr;
|
||||
auto continuing = continuing_stmt();
|
||||
if (has_error())
|
||||
return nullptr;
|
||||
|
||||
auto continuing = continuing_stmt();
|
||||
if (has_error())
|
||||
return nullptr;
|
||||
|
||||
t = next();
|
||||
if (!t.IsBraceRight()) {
|
||||
add_error(t, "missing } for loop");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::make_unique<ast::LoopStatement>(source, std::move(body),
|
||||
std::move(continuing));
|
||||
return std::make_unique<ast::LoopStatement>(source, std::move(body),
|
||||
std::move(continuing));
|
||||
});
|
||||
}
|
||||
|
||||
ForHeader::ForHeader(std::unique_ptr<ast::Statement> init,
|
||||
|
@ -2408,32 +2285,15 @@ std::unique_ptr<ast::Statement> ParserImpl::for_stmt() {
|
|||
if (!match(Token::Type::kFor, &source))
|
||||
return nullptr;
|
||||
|
||||
if (!expect("for loop", Token::Type::kParenLeft))
|
||||
auto header = expect_paren_block("for loop", [&] { return for_header(); });
|
||||
if (header == nullptr)
|
||||
return nullptr;
|
||||
|
||||
auto header = for_header();
|
||||
if (has_error())
|
||||
return nullptr;
|
||||
auto body = expect_brace_block("for loop", [&] { return statements(); });
|
||||
|
||||
if (!expect("for loop", Token::Type::kParenRight))
|
||||
if (body == nullptr)
|
||||
return nullptr;
|
||||
|
||||
auto t = next();
|
||||
if (!t.IsBraceLeft()) {
|
||||
add_error(t, "missing for loop {");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto body = statements();
|
||||
if (has_error())
|
||||
return nullptr;
|
||||
|
||||
t = next();
|
||||
if (!t.IsBraceRight()) {
|
||||
add_error(t, "missing for loop }");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// The for statement is a syntactic sugar on top of the loop statement.
|
||||
// We create corresponding nodes in ast with the exact same behaviour
|
||||
// as we would expect from the loop statement.
|
||||
|
@ -2609,19 +2469,21 @@ std::unique_ptr<ast::Expression> ParserImpl::primary_expression() {
|
|||
if (has_error())
|
||||
return nullptr;
|
||||
if (type != nullptr) {
|
||||
if (!expect("type constructor", Token::Type::kParenLeft))
|
||||
return nullptr;
|
||||
|
||||
t = peek();
|
||||
ast::ExpressionList params;
|
||||
if (!t.IsParenRight() && !t.IsEof()) {
|
||||
params = argument_expression_list();
|
||||
if (has_error())
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!expect("type constructor", Token::Type::kParenRight))
|
||||
auto ok = expect_paren_block("type constructor", [&] {
|
||||
t = peek();
|
||||
if (!t.IsParenRight() && !t.IsEof()) {
|
||||
params = argument_expression_list();
|
||||
if (has_error())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!ok) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::make_unique<ast::TypeConstructorExpression>(source, type,
|
||||
std::move(params));
|
||||
|
@ -3271,36 +3133,30 @@ std::unique_ptr<ast::ConstructorExpression> ParserImpl::const_expr_internal(
|
|||
|
||||
auto* type = type_decl();
|
||||
if (type != nullptr) {
|
||||
if (!expect("type constructor", Token::Type::kParenLeft))
|
||||
return nullptr;
|
||||
|
||||
ast::ExpressionList params;
|
||||
auto param = const_expr_internal(depth + 1);
|
||||
if (has_error())
|
||||
return nullptr;
|
||||
if (param == nullptr) {
|
||||
add_error(peek(), "unable to parse constant expression");
|
||||
return nullptr;
|
||||
}
|
||||
params.push_back(std::move(param));
|
||||
for (;;) {
|
||||
t = peek();
|
||||
if (!t.IsComma())
|
||||
break;
|
||||
|
||||
next(); // Consume the peek
|
||||
|
||||
param = const_expr_internal(depth + 1);
|
||||
bool ok = expect_paren_block("type constructor", [&] {
|
||||
auto param = const_expr_internal(depth + 1);
|
||||
if (has_error())
|
||||
return nullptr;
|
||||
return false;
|
||||
if (param == nullptr) {
|
||||
add_error(peek(), "unable to parse constant expression");
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
params.push_back(std::move(param));
|
||||
}
|
||||
while (match(Token::Type::kComma)) {
|
||||
param = const_expr_internal(depth + 1);
|
||||
if (has_error())
|
||||
return false;
|
||||
if (param == nullptr) {
|
||||
add_error(peek(), "unable to parse constant expression");
|
||||
return false;
|
||||
}
|
||||
params.push_back(std::move(param));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!expect("type constructor", Token::Type::kParenRight))
|
||||
if (!ok)
|
||||
return nullptr;
|
||||
|
||||
return std::make_unique<ast::TypeConstructorExpression>(source, type,
|
||||
|
@ -3401,6 +3257,36 @@ bool ParserImpl::expect_ident(const std::string& use,
|
|||
return true;
|
||||
}
|
||||
|
||||
template <typename F, typename T>
|
||||
T ParserImpl::expect_block(Token::Type start,
|
||||
Token::Type end,
|
||||
const std::string& use,
|
||||
F&& body) {
|
||||
if (!expect(use, start)) {
|
||||
return {};
|
||||
}
|
||||
auto res = body();
|
||||
if (has_error()) {
|
||||
return {};
|
||||
}
|
||||
if (!expect(use, end)) {
|
||||
return {};
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename F, typename T>
|
||||
T ParserImpl::expect_paren_block(const std::string& use, F&& body) {
|
||||
return expect_block(Token::Type::kParenLeft, Token::Type::kParenRight, use,
|
||||
std::forward<F>(body));
|
||||
}
|
||||
|
||||
template <typename F, typename T>
|
||||
T ParserImpl::expect_brace_block(const std::string& use, F&& body) {
|
||||
return expect_block(Token::Type::kBraceLeft, Token::Type::kBraceRight, use,
|
||||
std::forward<F>(body));
|
||||
}
|
||||
|
||||
} // namespace wgsl
|
||||
} // namespace reader
|
||||
} // namespace tint
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <deque>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
|
@ -435,6 +436,10 @@ class ParserImpl {
|
|||
std::unique_ptr<ast::AssignmentStatement> assignment_stmt();
|
||||
|
||||
private:
|
||||
/// ResultType resolves to the return type for the function or lambda F.
|
||||
template <typename F>
|
||||
using ResultType = typename std::result_of<F()>::type;
|
||||
|
||||
/// @returns true and consumes the next token if it equals |tok|.
|
||||
/// @param source if not nullptr, the next token's source is written to this
|
||||
/// pointer, regardless of success or error
|
||||
|
@ -476,6 +481,45 @@ class ParserImpl {
|
|||
bool expect_ident(const std::string& use,
|
||||
std::string* out,
|
||||
Source* source = nullptr);
|
||||
/// Parses a lexical block starting with the token |start| and ending with
|
||||
/// the token |end|. |body| is called to parse the lexical block body between
|
||||
/// the |start| and |end| tokens.
|
||||
/// If the |start| or |end| tokens are not matched then an error is generated
|
||||
/// and a zero-initialized |T| is returned.
|
||||
/// If |body| raises an error while parsing then a zero-initialized |T| is
|
||||
/// returned.
|
||||
/// @param start the token that begins the lexical block
|
||||
/// @param end the token that ends the lexical block
|
||||
/// @param use a description of what was being parsed if an error was raised
|
||||
/// @param body a function or lambda that is called to parse the lexical block
|
||||
/// body, with the signature T().
|
||||
/// @return the value returned by |body| if no errors are raised, otherwise
|
||||
/// a zero-initialized |T|.
|
||||
template <typename F, typename T = ResultType<F>>
|
||||
T expect_block(Token::Type start,
|
||||
Token::Type end,
|
||||
const std::string& use,
|
||||
F&& body);
|
||||
/// A convenience function that calls |expect_block| passing
|
||||
/// |Token::Type::kParenLeft| and |Token::Type::kParenRight| for the |start|
|
||||
/// and |end| arguments, respectively.
|
||||
/// @param use a description of what was being parsed if an error was raised
|
||||
/// @param body a function or lambda that is called to parse the lexical block
|
||||
/// body, with the signature T().
|
||||
/// @return the value returned by |body| if no errors are raised, otherwise
|
||||
/// a zero-initialized |T|.
|
||||
template <typename F, typename T = ResultType<F>>
|
||||
T expect_paren_block(const std::string& use, F&& body);
|
||||
/// A convenience function that calls |expect_block| passing
|
||||
/// |Token::Type::kBraceLeft| and |Token::Type::kBraceRight| for the |start|
|
||||
/// and |end| arguments, respectively.
|
||||
/// @param use a description of what was being parsed if an error was raised
|
||||
/// @param body a function or lambda that is called to parse the lexical block
|
||||
/// body, with the signature T().
|
||||
/// @return the value returned by |body| if no errors are raised, otherwise
|
||||
/// a zero-initialized |T|.
|
||||
template <typename F, typename T = ResultType<F>>
|
||||
T expect_brace_block(const std::string& use, F&& body);
|
||||
|
||||
ast::type::Type* type_decl_pointer(Token t);
|
||||
ast::type::Type* type_decl_vector(Token t);
|
||||
|
|
|
@ -44,14 +44,14 @@ TEST_F(ParserImplTest, BodyStmt_InvalidStmt) {
|
|||
auto* p = parser("{fn main() -> void {}}");
|
||||
auto e = p->body_stmt();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
EXPECT_EQ(p->error(), "1:2: missing }");
|
||||
EXPECT_EQ(p->error(), "1:2: expected '}'");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, BodyStmt_MissingRightParen) {
|
||||
auto* p = parser("{return;");
|
||||
auto e = p->body_stmt();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
EXPECT_EQ(p->error(), "1:9: missing }");
|
||||
EXPECT_EQ(p->error(), "1:9: expected '}'");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -37,7 +37,7 @@ TEST_F(ParserImplTest, ElseStmt_InvalidBody) {
|
|||
auto e = p->else_stmt();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(e, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:8: missing }");
|
||||
EXPECT_EQ(p->error(), "1:8: expected '}'");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, ElseStmt_MissingBody) {
|
||||
|
@ -45,7 +45,7 @@ TEST_F(ParserImplTest, ElseStmt_MissingBody) {
|
|||
auto e = p->else_stmt();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(e, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:5: missing {");
|
||||
EXPECT_EQ(p->error(), "1:5: expected '{'");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -55,14 +55,14 @@ TEST_F(ParserImplTest, ElseIfStmt_InvalidBody) {
|
|||
auto* p = parser("elseif (true) { fn main() -> void {}}");
|
||||
auto e = p->elseif_stmt();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
EXPECT_EQ(p->error(), "1:17: missing }");
|
||||
EXPECT_EQ(p->error(), "1:17: expected '}'");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, ElseIfStmt_MissingBody) {
|
||||
auto* p = parser("elseif (true)");
|
||||
auto e = p->elseif_stmt();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
EXPECT_EQ(p->error(), "1:14: missing {");
|
||||
EXPECT_EQ(p->error(), "1:14: expected '{'");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -239,14 +239,14 @@ TEST_F(ParserImplErrorTest, ForLoopMissingRParen) {
|
|||
|
||||
TEST_F(ParserImplErrorTest, ForLoopMissingLBrace) {
|
||||
EXPECT("fn f() -> void { for (var i : i32 = 0; i < 8; i=i+1) } }",
|
||||
"test.wgsl:1:54 error: missing for loop {\n"
|
||||
"test.wgsl:1:54 error: expected '{' for for loop\n"
|
||||
"fn f() -> void { for (var i : i32 = 0; i < 8; i=i+1) } }\n"
|
||||
" ^\n");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplErrorTest, ForLoopMissingRBrace) {
|
||||
EXPECT("fn f() -> void { for (var i : i32 = 0; i < 8; i=i+1) {",
|
||||
"test.wgsl:1:55 error: missing for loop }\n"
|
||||
"test.wgsl:1:55 error: expected '}' for for loop\n"
|
||||
"fn f() -> void { for (var i : i32 = 0; i < 8; i=i+1) {\n"
|
||||
" ^\n");
|
||||
}
|
||||
|
@ -438,14 +438,14 @@ TEST_F(ParserImplErrorTest, FunctionDeclParamMissing) {
|
|||
|
||||
TEST_F(ParserImplErrorTest, FunctionDeclMissingLBrace) {
|
||||
EXPECT("fn f() -> void }",
|
||||
"test.wgsl:1:16 error: missing {\n"
|
||||
"test.wgsl:1:16 error: expected '{'\n"
|
||||
"fn f() -> void }\n"
|
||||
" ^\n");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplErrorTest, FunctionDeclMissingRBrace) {
|
||||
EXPECT("fn f() -> void {",
|
||||
"test.wgsl:1:17 error: missing }\n"
|
||||
"test.wgsl:1:17 error: expected '}'\n"
|
||||
"fn f() -> void {\n"
|
||||
" ^\n");
|
||||
}
|
||||
|
@ -647,14 +647,14 @@ TEST_F(ParserImplErrorTest, GlobalDeclStructDeclMissingSemicolon) {
|
|||
|
||||
TEST_F(ParserImplErrorTest, GlobalDeclStructDeclMissingLBrace) {
|
||||
EXPECT("struct S };",
|
||||
"test.wgsl:1:10 error: missing { for struct declaration\n"
|
||||
"test.wgsl:1:10 error: expected '{' for struct declaration\n"
|
||||
"struct S };\n"
|
||||
" ^\n");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplErrorTest, GlobalDeclStructDeclMissingRBrace) {
|
||||
EXPECT("struct S { i : i32;",
|
||||
"test.wgsl:1:20 error: missing } for struct declaration\n"
|
||||
"test.wgsl:1:20 error: expected '}' for struct declaration\n"
|
||||
"struct S { i : i32;\n"
|
||||
" ^\n");
|
||||
}
|
||||
|
@ -1101,14 +1101,14 @@ TEST_F(ParserImplErrorTest, LogicalOrInvalidExpr) {
|
|||
|
||||
TEST_F(ParserImplErrorTest, LoopMissingLBrace) {
|
||||
EXPECT("fn f() -> void { loop } }",
|
||||
"test.wgsl:1:23 error: missing { for loop\n"
|
||||
"test.wgsl:1:23 error: expected '{' for loop\n"
|
||||
"fn f() -> void { loop } }\n"
|
||||
" ^\n");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplErrorTest, LoopMissingRBrace) {
|
||||
EXPECT("fn f() -> void { loop {",
|
||||
"test.wgsl:1:24 error: missing } for loop\n"
|
||||
"test.wgsl:1:24 error: expected '}' for loop\n"
|
||||
"fn f() -> void { loop {\n"
|
||||
" ^\n");
|
||||
}
|
||||
|
@ -1157,14 +1157,14 @@ TEST_F(ParserImplErrorTest, ShiftInvalidExpr) {
|
|||
|
||||
TEST_F(ParserImplErrorTest, SwitchStmtMissingLBrace) {
|
||||
EXPECT("fn f() -> void { switch(1) }",
|
||||
"test.wgsl:1:28 error: missing { for switch statement\n"
|
||||
"test.wgsl:1:28 error: expected '{' for switch statement\n"
|
||||
"fn f() -> void { switch(1) }\n"
|
||||
" ^\n");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplErrorTest, SwitchStmtMissingRBrace) {
|
||||
EXPECT("fn f() -> void { switch(1) {",
|
||||
"test.wgsl:1:29 error: missing } for switch statement\n"
|
||||
"test.wgsl:1:29 error: expected '}' for switch statement\n"
|
||||
"fn f() -> void { switch(1) {\n"
|
||||
" ^\n");
|
||||
}
|
||||
|
@ -1186,21 +1186,21 @@ TEST_F(ParserImplErrorTest, SwitchStmtInvalidCase2) {
|
|||
|
||||
TEST_F(ParserImplErrorTest, SwitchStmtCaseMissingColon) {
|
||||
EXPECT("fn f() -> void { switch(1) { case 1 {} } }",
|
||||
"test.wgsl:1:37 error: missing : for case statement\n"
|
||||
"test.wgsl:1:37 error: expected ':' for case statement\n"
|
||||
"fn f() -> void { switch(1) { case 1 {} } }\n"
|
||||
" ^\n");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplErrorTest, SwitchStmtCaseMissingLBrace) {
|
||||
EXPECT("fn f() -> void { switch(1) { case 1: } } }",
|
||||
"test.wgsl:1:38 error: missing { for case statement\n"
|
||||
"test.wgsl:1:38 error: expected '{' for case statement\n"
|
||||
"fn f() -> void { switch(1) { case 1: } } }\n"
|
||||
" ^\n");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplErrorTest, SwitchStmtCaseMissingRBrace) {
|
||||
EXPECT("fn f() -> void { switch(1) { case 1: {",
|
||||
"test.wgsl:1:39 error: missing } for case statement\n"
|
||||
"test.wgsl:1:39 error: expected '}' for case statement\n"
|
||||
"fn f() -> void { switch(1) { case 1: {\n"
|
||||
" ^\n");
|
||||
}
|
||||
|
|
|
@ -200,7 +200,7 @@ TEST_F(ForStmtErrorTest, MissingRightParen) {
|
|||
// Test a for loop with missing left brace is invalid.
|
||||
TEST_F(ForStmtErrorTest, MissingLeftBrace) {
|
||||
std::string for_str = "for (;;)";
|
||||
std::string error_str = "1:9: missing for loop {";
|
||||
std::string error_str = "1:9: expected '{' for for loop";
|
||||
|
||||
TestForWithError(for_str, error_str);
|
||||
}
|
||||
|
@ -208,7 +208,7 @@ TEST_F(ForStmtErrorTest, MissingLeftBrace) {
|
|||
// Test a for loop with missing right brace is invalid.
|
||||
TEST_F(ForStmtErrorTest, MissingRightBrace) {
|
||||
std::string for_str = "for (;;) {";
|
||||
std::string error_str = "1:11: missing for loop }";
|
||||
std::string error_str = "1:11: expected '}' for for loop";
|
||||
|
||||
TestForWithError(for_str, error_str);
|
||||
}
|
||||
|
@ -275,7 +275,7 @@ TEST_F(ForStmtErrorTest, InvalidBody) {
|
|||
// Test a for loop with a body not matching statements
|
||||
TEST_F(ForStmtErrorTest, InvalidBodyMatch) {
|
||||
std::string for_str = "for (;;) { fn main() -> void {} }";
|
||||
std::string error_str = "1:12: missing for loop }";
|
||||
std::string error_str = "1:12: expected '}' for for loop";
|
||||
|
||||
TestForWithError(for_str, error_str);
|
||||
}
|
||||
|
|
|
@ -174,7 +174,7 @@ TEST_F(ParserImplTest, FunctionDecl_MissingLeftBrace) {
|
|||
auto f = p->function_decl();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(f, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:19: missing {");
|
||||
EXPECT_EQ(p->error(), "1:19: expected '{'");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -78,7 +78,7 @@ TEST_F(ParserImplTest, IfStmt_InvalidBody) {
|
|||
auto e = p->if_stmt();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(e, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:10: missing }");
|
||||
EXPECT_EQ(p->error(), "1:10: expected '}'");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, IfStmt_MissingBody) {
|
||||
|
@ -86,7 +86,7 @@ TEST_F(ParserImplTest, IfStmt_MissingBody) {
|
|||
auto e = p->if_stmt();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(e, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:7: missing {");
|
||||
EXPECT_EQ(p->error(), "1:7: expected '{'");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, IfStmt_InvalidElseif) {
|
||||
|
@ -94,7 +94,7 @@ TEST_F(ParserImplTest, IfStmt_InvalidElseif) {
|
|||
auto e = p->if_stmt();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(e, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:24: missing }");
|
||||
EXPECT_EQ(p->error(), "1:24: expected '}'");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, IfStmt_InvalidElse) {
|
||||
|
@ -102,7 +102,7 @@ TEST_F(ParserImplTest, IfStmt_InvalidElse) {
|
|||
auto e = p->if_stmt();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(e, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:18: missing }");
|
||||
EXPECT_EQ(p->error(), "1:18: expected '}'");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -70,7 +70,7 @@ TEST_F(ParserImplTest, LoopStmt_MissingBracketLeft) {
|
|||
auto e = p->loop_stmt();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(e, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:6: missing { for loop");
|
||||
EXPECT_EQ(p->error(), "1:6: expected '{' for loop");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, LoopStmt_MissingBracketRight) {
|
||||
|
@ -78,7 +78,7 @@ TEST_F(ParserImplTest, LoopStmt_MissingBracketRight) {
|
|||
auto e = p->loop_stmt();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(e, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:17: missing } for loop");
|
||||
EXPECT_EQ(p->error(), "1:17: expected '}' for loop");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, LoopStmt_InvalidStatements) {
|
||||
|
|
|
@ -90,7 +90,7 @@ TEST_F(ParserImplTest, Statement_If_Invalid) {
|
|||
auto e = p->statement();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(e, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:10: missing }");
|
||||
EXPECT_EQ(p->error(), "1:10: expected '}'");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, Statement_Variable) {
|
||||
|
@ -146,7 +146,7 @@ TEST_F(ParserImplTest, Statement_Loop_Invalid) {
|
|||
auto e = p->statement();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(e, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:6: missing { for loop");
|
||||
EXPECT_EQ(p->error(), "1:6: expected '{' for loop");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, Statement_Assignment) {
|
||||
|
@ -235,7 +235,7 @@ TEST_F(ParserImplTest, Statement_Body_Invalid) {
|
|||
auto e = p->statement();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(e, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:3: missing }");
|
||||
EXPECT_EQ(p->error(), "1:3: expected '}'");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -59,7 +59,7 @@ TEST_F(ParserImplTest, StructBodyDecl_MissingClosingBracket) {
|
|||
auto* p = parser("{a : i32;");
|
||||
auto m = p->struct_body_decl();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
EXPECT_EQ(p->error(), "1:10: missing } for struct declaration");
|
||||
EXPECT_EQ(p->error(), "1:10: expected '}' for struct declaration");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, StructBodyDecl_InvalidToken) {
|
||||
|
|
|
@ -94,7 +94,7 @@ TEST_F(ParserImplTest, StructDecl_MissingBracketLeft) {
|
|||
auto s = p->struct_decl();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(s, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:10: missing { for struct declaration");
|
||||
EXPECT_EQ(p->error(), "1:10: expected '{' for struct declaration");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, StructDecl_InvalidStructBody) {
|
||||
|
|
|
@ -62,7 +62,7 @@ TEST_F(ParserImplTest, SwitchBody_Case_MissingColon) {
|
|||
auto e = p->switch_body();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(e, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:8: missing : for case statement");
|
||||
EXPECT_EQ(p->error(), "1:8: expected ':' for case statement");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, SwitchBody_Case_MissingBracketLeft) {
|
||||
|
@ -70,7 +70,7 @@ TEST_F(ParserImplTest, SwitchBody_Case_MissingBracketLeft) {
|
|||
auto e = p->switch_body();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(e, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:9: missing { for case statement");
|
||||
EXPECT_EQ(p->error(), "1:9: expected '{' for case statement");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, SwitchBody_Case_MissingBracketRight) {
|
||||
|
@ -78,7 +78,7 @@ TEST_F(ParserImplTest, SwitchBody_Case_MissingBracketRight) {
|
|||
auto e = p->switch_body();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(e, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:18: missing } for case statement");
|
||||
EXPECT_EQ(p->error(), "1:18: expected '}' for case statement");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, SwitchBody_Case_InvalidCaseBody) {
|
||||
|
@ -86,7 +86,7 @@ TEST_F(ParserImplTest, SwitchBody_Case_InvalidCaseBody) {
|
|||
auto e = p->switch_body();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(e, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:11: missing } for case statement");
|
||||
EXPECT_EQ(p->error(), "1:11: expected '}' for case statement");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, SwitchBody_Default) {
|
||||
|
@ -105,7 +105,7 @@ TEST_F(ParserImplTest, SwitchBody_Default_MissingColon) {
|
|||
auto e = p->switch_body();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(e, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:9: missing : for case statement");
|
||||
EXPECT_EQ(p->error(), "1:9: expected ':' for case statement");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, SwitchBody_Default_MissingBracketLeft) {
|
||||
|
@ -113,7 +113,7 @@ TEST_F(ParserImplTest, SwitchBody_Default_MissingBracketLeft) {
|
|||
auto e = p->switch_body();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(e, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:10: missing { for case statement");
|
||||
EXPECT_EQ(p->error(), "1:10: expected '{' for case statement");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, SwitchBody_Default_MissingBracketRight) {
|
||||
|
@ -121,7 +121,7 @@ TEST_F(ParserImplTest, SwitchBody_Default_MissingBracketRight) {
|
|||
auto e = p->switch_body();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(e, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:19: missing } for case statement");
|
||||
EXPECT_EQ(p->error(), "1:19: expected '}' for case statement");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, SwitchBody_Default_InvalidCaseBody) {
|
||||
|
@ -129,7 +129,7 @@ TEST_F(ParserImplTest, SwitchBody_Default_InvalidCaseBody) {
|
|||
auto e = p->switch_body();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(e, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:12: missing } for case statement");
|
||||
EXPECT_EQ(p->error(), "1:12: expected '}' for case statement");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -84,7 +84,7 @@ TEST_F(ParserImplTest, SwitchStmt_MissingBracketLeft) {
|
|||
auto e = p->switch_stmt();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(e, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:11: missing { for switch statement");
|
||||
EXPECT_EQ(p->error(), "1:11: expected '{' for switch statement");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, SwitchStmt_MissingBracketRight) {
|
||||
|
@ -92,7 +92,7 @@ TEST_F(ParserImplTest, SwitchStmt_MissingBracketRight) {
|
|||
auto e = p->switch_stmt();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(e, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:12: missing } for switch statement");
|
||||
EXPECT_EQ(p->error(), "1:12: expected '}' for switch statement");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, SwitchStmt_InvalidBody) {
|
||||
|
|
Loading…
Reference in New Issue