wsgl parser: expect for variable_ident_decl

All the call sites of `variable_ident_decl()` add their own error handling, so transform this into `expect_variable_ident_decl()`.

Also makes error messages more consistent.

Bug: tint:282
Change-Id: I0b5ac984018ba78896ddec0320636f5b5c4ad0b2
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/32100
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
This commit is contained in:
Ben Clayton 2020-11-09 18:41:23 +00:00 committed by Commit Bot service account
parent 6512327f01
commit b8df12042a
12 changed files with 89 additions and 115 deletions

View File

@ -123,7 +123,7 @@ ParserImpl::ParserImpl(Context* ctx, Source::File const* file)
ParserImpl::~ParserImpl() = default; ParserImpl::~ParserImpl() = default;
void ParserImpl::add_error(const Token& t, void ParserImpl::add_error(const Source& source,
const std::string& err, const std::string& err,
const std::string& use) { const std::string& use) {
std::stringstream msg; std::stringstream msg;
@ -131,7 +131,7 @@ void ParserImpl::add_error(const Token& t,
if (!use.empty()) { if (!use.empty()) {
msg << " for " << use; msg << " for " << use;
} }
add_error(t, msg.str()); add_error(source, msg.str());
} }
void ParserImpl::add_error(const Token& t, const std::string& err) { void ParserImpl::add_error(const Token& t, const std::string& err) {
@ -317,27 +317,23 @@ std::unique_ptr<ast::Variable> ParserImpl::global_constant_decl() {
if (!match(Token::Type::kConst)) if (!match(Token::Type::kConst))
return nullptr; return nullptr;
auto decl = variable_ident_decl(); const char* use = "constant declaration";
auto decl = expect_variable_ident_decl(use);
if (has_error()) if (has_error())
return nullptr; return nullptr;
if (decl.name.empty() || decl.type == nullptr) {
add_error(peek(), "error parsing constant variable identifier");
return nullptr;
}
auto var = std::make_unique<ast::Variable>( auto var = std::make_unique<ast::Variable>(
decl.source, decl.name, ast::StorageClass::kNone, decl.type); decl.source, decl.name, ast::StorageClass::kNone, decl.type);
var->set_is_const(true); var->set_is_const(true);
auto t = next(); if (!expect(use, Token::Type::kEqual))
if (!t.IsEqual()) {
add_error(t, "missing = for const declaration");
return nullptr; return nullptr;
}
auto init = expect_const_expr(); auto init = expect_const_expr();
if (has_error()) if (has_error())
return nullptr; return nullptr;
var->set_constructor(std::move(init)); var->set_constructor(std::move(init));
return var; return var;
@ -351,15 +347,11 @@ std::unique_ptr<ast::Variable> ParserImpl::variable_decl() {
auto sc = variable_storage_decoration(); auto sc = variable_storage_decoration();
if (has_error()) if (has_error())
return {}; return nullptr;
auto decl = variable_ident_decl(); auto decl = expect_variable_ident_decl("variable declaration");
if (has_error()) if (has_error())
return nullptr; return nullptr;
if (decl.name.empty() || decl.type == nullptr) {
add_error(peek(), "invalid identifier declaration");
return nullptr;
}
return std::make_unique<ast::Variable>(decl.source, decl.name, sc, decl.type); return std::make_unique<ast::Variable>(decl.source, decl.name, sc, decl.type);
} }
@ -753,26 +745,22 @@ ast::type::ImageFormat ParserImpl::image_storage_type() {
// variable_ident_decl // variable_ident_decl
// : IDENT COLON type_decl // : IDENT COLON type_decl
ParserImpl::TypedIdentifier ParserImpl::variable_ident_decl() { ParserImpl::TypedIdentifier ParserImpl::expect_variable_ident_decl(
const std::string& use) {
std::string name;
Source source;
if (!expect_ident(use, &name, &source))
return {};
if (!expect(use, Token::Type::kColon))
return {};
auto t = peek(); auto t = peek();
if (!t.IsIdentifier())
return {};
auto name = t.to_str();
auto source = t.source();
next(); // Consume the peek
t = next();
if (!t.IsColon()) {
add_error(t, "missing : for identifier declaration");
return {};
}
auto* type = type_decl(); auto* type = type_decl();
if (has_error()) if (has_error())
return {}; return {};
if (type == nullptr) { if (type == nullptr) {
add_error(peek(), "invalid type for identifier declaration"); add_error(t.source(), "invalid type", use);
return {}; return {};
} }
@ -894,9 +882,8 @@ ast::type::Type* ParserImpl::type_decl() {
} }
auto decos = decoration_list(); auto decos = decoration_list();
if (has_error()) { if (has_error())
return nullptr; return nullptr;
}
if (match(Token::Type::kArray)) { if (match(Token::Type::kArray)) {
auto array_decos = cast_decorations<ast::ArrayDecoration>(decos); auto array_decos = cast_decorations<ast::ArrayDecoration>(decos);
@ -1133,9 +1120,8 @@ std::unique_ptr<ast::type::StructType> ParserImpl::struct_decl(
return nullptr; return nullptr;
auto body = expect_struct_body_decl(); auto body = expect_struct_body_decl();
if (has_error()) { if (has_error())
return nullptr; return nullptr;
}
return std::make_unique<ast::type::StructType>( return std::make_unique<ast::type::StructType>(
name, std::make_unique<ast::Struct>(source, std::move(struct_decos), name, std::make_unique<ast::Struct>(source, std::move(struct_decos),
@ -1150,6 +1136,8 @@ ast::StructMemberList ParserImpl::expect_struct_body_decl() {
while (!peek().IsBraceRight() && !peek().IsEof()) { while (!peek().IsBraceRight() && !peek().IsEof()) {
auto decos = decoration_list(); auto decos = decoration_list();
if (has_error())
return ast::StructMemberList{};
auto mem = expect_struct_member(decos); auto mem = expect_struct_member(decos);
if (has_error()) if (has_error())
@ -1166,15 +1154,23 @@ ast::StructMemberList ParserImpl::expect_struct_body_decl() {
// : struct_member_decoration_decl+ variable_ident_decl SEMICOLON // : struct_member_decoration_decl+ variable_ident_decl SEMICOLON
std::unique_ptr<ast::StructMember> ParserImpl::expect_struct_member( std::unique_ptr<ast::StructMember> ParserImpl::expect_struct_member(
ast::DecorationList& decos) { ast::DecorationList& decos) {
auto t = peek(); // FUDGE - Abort early if we enter with an error state to avoid accumulating
// multiple error messages. This is a work around for the unit tests that
auto decl = variable_ident_decl(); // call:
// auto decos = p->decoration_list();
// auto m = p->expect_struct_member(decos);
// ... and expect a single error message due to bad decorations.
// While expect_struct_body_decl() aborts after checking for decoration parse
// errors (and so these tests do not currently reflect full-parse behaviour),
// they do test the long-term desired behavior where the parser can
// resynchronize at the ']]'.
// TODO(ben-clayton) - remove this once resynchronization is implemented.
if (has_error()) if (has_error())
return nullptr; return nullptr;
if (decl.name.empty() || decl.type == nullptr) {
add_error(peek(), "invalid identifier declaration"); auto decl = expect_variable_ident_decl("struct member");
if (has_error())
return nullptr; return nullptr;
}
auto member_decos = cast_decorations<ast::StructMemberDecoration>(decos); auto member_decos = cast_decorations<ast::StructMemberDecoration>(decos);
@ -1255,16 +1251,14 @@ std::unique_ptr<ast::Function> ParserImpl::function_header() {
// : // :
// | (variable_ident_decl COMMA)* variable_ident_decl // | (variable_ident_decl COMMA)* variable_ident_decl
ast::VariableList ParserImpl::expect_param_list() { ast::VariableList ParserImpl::expect_param_list() {
auto t = peek(); if (!peek().IsIdentifier()) // Empty list
return ast::VariableList{};
ast::VariableList ret; auto decl = expect_variable_ident_decl("parameter");
auto decl = variable_ident_decl();
if (has_error()) if (has_error())
return {}; return {};
if (decl.name.empty() || decl.type == nullptr)
return {};
ast::VariableList ret;
for (;;) { for (;;) {
auto var = std::make_unique<ast::Variable>( auto var = std::make_unique<ast::Variable>(
decl.source, decl.name, ast::StorageClass::kNone, decl.type); decl.source, decl.name, ast::StorageClass::kNone, decl.type);
@ -1275,19 +1269,12 @@ ast::VariableList ParserImpl::expect_param_list() {
var->set_is_const(true); var->set_is_const(true);
ret.push_back(std::move(var)); ret.push_back(std::move(var));
t = peek(); if (!match(Token::Type::kComma))
if (!t.IsComma())
break; break;
next(); // Consume the peek decl = expect_variable_ident_decl("parameter");
decl = variable_ident_decl();
if (has_error()) if (has_error())
return {}; return {};
if (decl.name.empty() || decl.type == nullptr) {
add_error(t, "found , but no variable declaration");
return {};
}
} }
return ret; return ret;
@ -1518,19 +1505,12 @@ std::unique_ptr<ast::VariableDeclStatement> ParserImpl::variable_stmt() {
if (t.IsConst()) { if (t.IsConst()) {
next(); // Consume the peek next(); // Consume the peek
auto decl = variable_ident_decl(); auto decl = expect_variable_ident_decl("constant declaration");
if (has_error()) if (has_error())
return nullptr; return nullptr;
if (decl.name.empty() || decl.type == nullptr) {
add_error(peek(), "unable to parse variable declaration");
return nullptr;
}
t = next(); if (!expect("constant declaration", Token::Type::kEqual))
if (!t.IsEqual()) {
add_error(t, "missing = for constant declaration");
return nullptr; return nullptr;
}
auto constructor = logical_or_expression(); auto constructor = logical_or_expression();
if (has_error()) if (has_error())
@ -2760,9 +2740,9 @@ bool ParserImpl::decoration_bracketed_list(ast::DecorationList& decos) {
return false; return false;
} }
auto t = peek(); Source source;
if (match(Token::Type::kAttrRight)) { if (match(Token::Type::kAttrRight, &source)) {
add_error(t, "empty decoration list"); add_error(source, "empty decoration list");
return false; return false;
} }
@ -2954,7 +2934,7 @@ bool ParserImpl::expect(const std::string& use, Token::Type tok) {
bool ParserImpl::expect_sint(const std::string& use, int32_t* out) { bool ParserImpl::expect_sint(const std::string& use, int32_t* out) {
auto t = next(); auto t = next();
if (!t.IsSintLiteral()) { if (!t.IsSintLiteral()) {
add_error(t, "expected signed integer literal", use); add_error(t.source(), "expected signed integer literal", use);
return false; return false;
} }
*out = t.to_i32(); *out = t.to_i32();
@ -2999,7 +2979,7 @@ bool ParserImpl::expect_ident(const std::string& use,
*source = t.source(); *source = t.source();
if (!t.IsIdentifier()) { if (!t.IsIdentifier()) {
add_error(t, "expected identifier", use); add_error(t.source(), "expected identifier", use);
return false; return false;
} }

View File

@ -132,11 +132,11 @@ class ParserImpl {
/// @param msg the error message /// @param msg the error message
void add_error(const Token& t, const std::string& msg); void add_error(const Token& t, const std::string& msg);
/// Appends an error raised when parsing |use| at |t| with the message |msg| /// Appends an error raised when parsing |use| at |t| with the message |msg|
/// @param t the token to associate the error with /// @param source the source to associate the error with
/// @param msg the error message /// @param msg the error message
/// @param use a description of what was being parsed when the error was /// @param use a description of what was being parsed when the error was
/// raised. /// raised.
void add_error(const Token& t, void add_error(const Source& source,
const std::string& msg, const std::string& msg,
const std::string& use); const std::string& use);
/// Appends an error at |source| with the message |msg| /// Appends an error at |source| with the message |msg|
@ -169,9 +169,11 @@ class ParserImpl {
/// Parses a `variable_decl` grammar element /// Parses a `variable_decl` grammar element
/// @returns the parsed variable or nullptr otherwise /// @returns the parsed variable or nullptr otherwise
std::unique_ptr<ast::Variable> variable_decl(); std::unique_ptr<ast::Variable> variable_decl();
/// Parses a `variable_ident_decl` grammar element /// Parses a `variable_ident_decl` grammar element, erroring on parse
/// failure.
/// @param use a description of what was being parsed if an error was raised.
/// @returns the identifier and type parsed or empty otherwise /// @returns the identifier and type parsed or empty otherwise
TypedIdentifier variable_ident_decl(); TypedIdentifier expect_variable_ident_decl(const std::string& use);
/// Parses a `variable_storage_decoration` grammar element /// Parses a `variable_storage_decoration` grammar element
/// @returns the storage class or StorageClass::kNone if none matched /// @returns the storage class or StorageClass::kNone if none matched
ast::StorageClass variable_storage_decoration(); ast::StorageClass variable_storage_decoration();

View File

@ -169,14 +169,14 @@ TEST_F(ParserImplErrorTest, ConstructorExprMissingRParen) {
TEST_F(ParserImplErrorTest, ConstVarStmtInvalid) { TEST_F(ParserImplErrorTest, ConstVarStmtInvalid) {
EXPECT("fn f() -> void { const >; }", EXPECT("fn f() -> void { const >; }",
"test.wgsl:1:24 error: unable to parse variable declaration\n" "test.wgsl:1:24 error: expected identifier for constant declaration\n"
"fn f() -> void { const >; }\n" "fn f() -> void { const >; }\n"
" ^\n"); " ^\n");
} }
TEST_F(ParserImplErrorTest, ConstVarStmtMissingAssignment) { TEST_F(ParserImplErrorTest, ConstVarStmtMissingAssignment) {
EXPECT("fn f() -> void { const a : i32; }", EXPECT("fn f() -> void { const a : i32; }",
"test.wgsl:1:31 error: missing = for constant declaration\n" "test.wgsl:1:31 error: expected '=' for constant declaration\n"
"fn f() -> void { const a : i32; }\n" "fn f() -> void { const a : i32; }\n"
" ^\n"); " ^\n");
} }
@ -416,23 +416,23 @@ TEST_F(ParserImplErrorTest, FunctionDeclInvalidReturnType) {
TEST_F(ParserImplErrorTest, FunctionDeclParamMissingColon) { TEST_F(ParserImplErrorTest, FunctionDeclParamMissingColon) {
EXPECT("fn f(x) -> void {}", EXPECT("fn f(x) -> void {}",
"test.wgsl:1:7 error: missing : for identifier declaration\n" "test.wgsl:1:7 error: expected ':' for parameter\n"
"fn f(x) -> void {}\n" "fn f(x) -> void {}\n"
" ^\n"); " ^\n");
} }
TEST_F(ParserImplErrorTest, FunctionDeclParamInvalidType) { TEST_F(ParserImplErrorTest, FunctionDeclParamInvalidType) {
EXPECT("fn f(x : 1) -> void {}", EXPECT("fn f(x : 1) -> void {}",
"test.wgsl:1:10 error: invalid type for identifier declaration\n" "test.wgsl:1:10 error: invalid type for parameter\n"
"fn f(x : 1) -> void {}\n" "fn f(x : 1) -> void {}\n"
" ^\n"); " ^\n");
} }
TEST_F(ParserImplErrorTest, FunctionDeclParamMissing) { TEST_F(ParserImplErrorTest, FunctionDeclParamMissing) {
EXPECT("fn f(x : i32, ) -> void {}", EXPECT("fn f(x : i32, ) -> void {}",
"test.wgsl:1:13 error: found , but no variable declaration\n" "test.wgsl:1:15 error: expected identifier for parameter\n"
"fn f(x : i32, ) -> void {}\n" "fn f(x : i32, ) -> void {}\n"
" ^\n"); " ^\n");
} }
TEST_F(ParserImplErrorTest, FunctionDeclMissingLBrace) { TEST_F(ParserImplErrorTest, FunctionDeclMissingLBrace) {
@ -451,7 +451,7 @@ TEST_F(ParserImplErrorTest, FunctionDeclMissingRBrace) {
TEST_F(ParserImplErrorTest, GlobalDeclConstInvalidIdentifier) { TEST_F(ParserImplErrorTest, GlobalDeclConstInvalidIdentifier) {
EXPECT("const ^ : i32 = 1;", EXPECT("const ^ : i32 = 1;",
"test.wgsl:1:7 error: error parsing constant variable identifier\n" "test.wgsl:1:7 error: expected identifier for constant declaration\n"
"const ^ : i32 = 1;\n" "const ^ : i32 = 1;\n"
" ^\n"); " ^\n");
} }
@ -479,7 +479,7 @@ TEST_F(ParserImplErrorTest, GlobalDeclConstMissingRParen) {
TEST_F(ParserImplErrorTest, GlobalDeclConstMissingAssignment) { TEST_F(ParserImplErrorTest, GlobalDeclConstMissingAssignment) {
EXPECT("const i : vec2<i32>;", EXPECT("const i : vec2<i32>;",
"test.wgsl:1:20 error: missing = for const declaration\n" "test.wgsl:1:20 error: expected '=' for constant declaration\n"
"const i : vec2<i32>;\n" "const i : vec2<i32>;\n"
" ^\n"); " ^\n");
} }
@ -702,7 +702,7 @@ TEST_F(ParserImplErrorTest, GlobalDeclStructMemberDecoMissingEnd) {
TEST_F(ParserImplErrorTest, GlobalDeclStructMemberInvalidIdentifier) { TEST_F(ParserImplErrorTest, GlobalDeclStructMemberInvalidIdentifier) {
EXPECT("struct S { 1 : i32; };", EXPECT("struct S { 1 : i32; };",
"test.wgsl:1:12 error: invalid identifier declaration\n" "test.wgsl:1:12 error: expected identifier for struct member\n"
"struct S { 1 : i32; };\n" "struct S { 1 : i32; };\n"
" ^\n"); " ^\n");
} }
@ -988,7 +988,7 @@ TEST_F(ParserImplErrorTest, GlobalDeclVarDecoBindingSetValue) {
TEST_F(ParserImplErrorTest, GlobalDeclVarInvalidIdentifier) { TEST_F(ParserImplErrorTest, GlobalDeclVarInvalidIdentifier) {
EXPECT("var ^ : mat4x4;", EXPECT("var ^ : mat4x4;",
"test.wgsl:1:5 error: invalid identifier declaration\n" "test.wgsl:1:5 error: expected identifier for variable declaration\n"
"var ^ : mat4x4;\n" "var ^ : mat4x4;\n"
" ^\n"); " ^\n");
} }

View File

@ -216,7 +216,7 @@ TEST_F(ForStmtErrorTest, MissingRightBrace) {
// Test a for loop with an invalid initializer statement. // Test a for loop with an invalid initializer statement.
TEST_F(ForStmtErrorTest, InvalidInitializerAsConstDecl) { TEST_F(ForStmtErrorTest, InvalidInitializerAsConstDecl) {
std::string for_str = "for (const x: i32;;) { }"; std::string for_str = "for (const x: i32;;) { }";
std::string error_str = "1:18: missing = for constant declaration"; std::string error_str = "1:18: expected '=' for constant declaration";
TestForWithError(for_str, error_str); TestForWithError(for_str, error_str);
} }
@ -267,7 +267,7 @@ TEST_F(ForStmtErrorTest, InvalidContinuingMatch) {
// Test a for loop with an invalid body. // Test a for loop with an invalid body.
TEST_F(ForStmtErrorTest, InvalidBody) { TEST_F(ForStmtErrorTest, InvalidBody) {
std::string for_str = "for (;;) { const x: i32; }"; std::string for_str = "for (;;) { const x: i32; }";
std::string error_str = "1:24: missing = for constant declaration"; std::string error_str = "1:24: expected '=' for constant declaration";
TestForWithError(for_str, error_str); TestForWithError(for_str, error_str);
} }

View File

@ -65,7 +65,7 @@ TEST_F(ParserImplTest, FunctionHeader_InvalidParamList) {
auto f = p->function_header(); auto f = p->function_header();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(f, nullptr); ASSERT_EQ(f, nullptr);
EXPECT_EQ(p->error(), "1:15: found , but no variable declaration"); EXPECT_EQ(p->error(), "1:16: expected identifier for parameter");
} }
TEST_F(ParserImplTest, FunctionHeader_MissingParenRight) { TEST_F(ParserImplTest, FunctionHeader_MissingParenRight) {

View File

@ -48,7 +48,7 @@ TEST_F(ParserImplTest, GlobalConstantDecl_MissingEqual) {
auto e = p->global_constant_decl(); auto e = p->global_constant_decl();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:14: missing = for const declaration"); EXPECT_EQ(p->error(), "1:14: expected '=' for constant declaration");
} }
TEST_F(ParserImplTest, GlobalConstantDecl_InvalidVariable) { TEST_F(ParserImplTest, GlobalConstantDecl_InvalidVariable) {

View File

@ -71,7 +71,7 @@ TEST_F(ParserImplTest, GlobalDecl_GlobalConstant_Invalid) {
auto* p = parser("const a : vec2<i32>;"); auto* p = parser("const a : vec2<i32>;");
p->expect_global_decl(); p->expect_global_decl();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:20: missing = for const declaration"); EXPECT_EQ(p->error(), "1:20: expected '=' for constant declaration");
} }
TEST_F(ParserImplTest, GlobalDecl_GlobalConstant_MissingSemicolon) { TEST_F(ParserImplTest, GlobalDecl_GlobalConstant_MissingSemicolon) {

View File

@ -87,7 +87,7 @@ TEST_F(ParserImplTest, ParamList_Multiple) {
TEST_F(ParserImplTest, ParamList_Empty) { TEST_F(ParserImplTest, ParamList_Empty) {
auto* p = parser(""); auto* p = parser("");
auto e = p->expect_param_list(); auto e = p->expect_param_list();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error());
EXPECT_EQ(e.size(), 0u); EXPECT_EQ(e.size(), 0u);
} }
@ -95,7 +95,7 @@ TEST_F(ParserImplTest, ParamList_HangingComma) {
auto* p = parser("a : i32,"); auto* p = parser("a : i32,");
auto e = p->expect_param_list(); auto e = p->expect_param_list();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:8: found , but no variable declaration"); EXPECT_EQ(p->error(), "1:9: expected identifier for parameter");
} }
} // namespace } // namespace

View File

@ -70,7 +70,7 @@ TEST_F(ParserImplTest, StructBodyDecl_InvalidToken) {
} )"); } )");
auto m = p->expect_struct_body_decl(); auto m = p->expect_struct_body_decl();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "4:3: invalid identifier declaration"); EXPECT_EQ(p->error(), "4:3: expected identifier for struct member");
} }
} // namespace } // namespace

View File

@ -52,7 +52,7 @@ TEST_F(ParserImplTest, VariableDecl_InvalidIdentDecl) {
auto v = p->variable_decl(); auto v = p->variable_decl();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(v, nullptr); ASSERT_EQ(v, nullptr);
ASSERT_EQ(p->error(), "1:12: missing : for identifier declaration"); ASSERT_EQ(p->error(), "1:12: expected ':' for variable declaration");
} }
TEST_F(ParserImplTest, VariableDecl_WithStorageClass) { TEST_F(ParserImplTest, VariableDecl_WithStorageClass) {

View File

@ -23,7 +23,7 @@ namespace {
TEST_F(ParserImplTest, VariableIdentDecl_Parses) { TEST_F(ParserImplTest, VariableIdentDecl_Parses) {
auto* p = parser("my_var : f32"); auto* p = parser("my_var : f32");
auto decl = p->variable_ident_decl(); auto decl = p->expect_variable_ident_decl("test");
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_EQ(decl.name, "my_var"); ASSERT_EQ(decl.name, "my_var");
ASSERT_NE(decl.type, nullptr); ASSERT_NE(decl.type, nullptr);
@ -37,43 +37,35 @@ TEST_F(ParserImplTest, VariableIdentDecl_Parses) {
TEST_F(ParserImplTest, VariableIdentDecl_MissingIdent) { TEST_F(ParserImplTest, VariableIdentDecl_MissingIdent) {
auto* p = parser(": f32"); auto* p = parser(": f32");
auto decl = p->variable_ident_decl(); auto decl = p->expect_variable_ident_decl("test");
ASSERT_FALSE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(decl.name, ""); ASSERT_EQ(p->error(), "1:1: expected identifier for test");
ASSERT_EQ(decl.type, nullptr);
auto t = p->next();
ASSERT_TRUE(t.IsColon());
} }
TEST_F(ParserImplTest, VariableIdentDecl_MissingColon) { TEST_F(ParserImplTest, VariableIdentDecl_MissingColon) {
auto* p = parser("my_var f32"); auto* p = parser("my_var f32");
auto r = p->variable_ident_decl(); auto r = p->expect_variable_ident_decl("test");
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:8: missing : for identifier declaration"); ASSERT_EQ(p->error(), "1:8: expected ':' for test");
} }
TEST_F(ParserImplTest, VariableIdentDecl_MissingType) { TEST_F(ParserImplTest, VariableIdentDecl_MissingType) {
auto* p = parser("my_var :"); auto* p = parser("my_var :");
auto r = p->variable_ident_decl(); auto r = p->expect_variable_ident_decl("test");
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:9: invalid type for identifier declaration"); ASSERT_EQ(p->error(), "1:9: invalid type for test");
} }
TEST_F(ParserImplTest, VariableIdentDecl_InvalidIdent) { TEST_F(ParserImplTest, VariableIdentDecl_InvalidIdent) {
auto* p = parser("123 : f32"); auto* p = parser("123 : f32");
auto decl = p->variable_ident_decl(); auto decl = p->expect_variable_ident_decl("test");
ASSERT_FALSE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(decl.name, ""); ASSERT_EQ(p->error(), "1:1: expected identifier for test");
ASSERT_EQ(decl.type, nullptr);
auto t = p->next();
ASSERT_TRUE(t.IsSintLiteral());
} }
TEST_F(ParserImplTest, VariableIdentDecl_InvalidType) { TEST_F(ParserImplTest, VariableIdentDecl_InvalidType) {
auto* p = parser("my_var : invalid"); auto* p = parser("my_var : invalid");
auto r = p->variable_ident_decl(); auto r = p->expect_variable_ident_decl("test");
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:10: unknown constructed type 'invalid'"); ASSERT_EQ(p->error(), "1:10: unknown constructed type 'invalid'");
} }

View File

@ -100,7 +100,7 @@ TEST_F(ParserImplTest, VariableStmt_Const_MissingEqual) {
auto e = p->variable_stmt(); auto e = p->variable_stmt();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:15: missing = for constant declaration"); EXPECT_EQ(p->error(), "1:15: expected '=' for constant declaration");
} }
TEST_F(ParserImplTest, VariableStmt_Const_MissingConstructor) { TEST_F(ParserImplTest, VariableStmt_Const_MissingConstructor) {