extracted and abstracted function

This commit is contained in:
Karma Riuk
2025-07-14 20:15:51 +02:00
parent f0f748f7f5
commit cbafb2e814
3 changed files with 43 additions and 38 deletions

View File

@@ -1,14 +1,10 @@
#include "ast/statements/let.hpp" #include "ast/statements/let.hpp"
#include "ast/ast.hpp" #include "ast/ast.hpp"
#include "ast/errors/error.hpp"
#include "lexer/lexer.hpp"
#include "parser/parser.hpp"
#include "utils.hpp" #include "utils.hpp"
#include <doctest.h> #include <doctest.h>
#include <memory> #include <memory>
#include <sstream>
void test_let_statement(ast::statement* stmt, const std::string name) { void test_let_statement(ast::statement* stmt, const std::string name) {
REQUIRE(stmt->token_literal() == "let"); REQUIRE(stmt->token_literal() == "let");
@@ -18,52 +14,22 @@ void test_let_statement(ast::statement* stmt, const std::string name) {
REQUIRE(let_stmt->name->token_literal() == name); REQUIRE(let_stmt->name->token_literal() == name);
} }
void test_failing_let_parsing(
std::string input_s,
std::vector<token::type> expected_types,
int n_good_statements = 0
) {
std::stringstream input(input_s);
lexer::lexer l{input};
parser::parser p{l};
std::unique_ptr<ast::program> program = p.parse_program();
// Check for errors
REQUIRE(p.errors.size() == expected_types.size());
int i = 0;
for (auto& e : p.errors) {
ast::error::expected_next* en = cast<ast::error::expected_next>(e);
REQUIRE(en->expected_type == expected_types[i++]);
}
// normal program check
REQUIRE_MESSAGE(
program != nullptr,
"parse_program() returned a null pointer"
);
REQUIRE(program->statements.size() == n_good_statements);
}
TEST_SUITE("Parser: let") { TEST_SUITE("Parser: let") {
TEST_CASE("Malformed let statement (checking for memory leaks)") { TEST_CASE("Malformed let statement (checking for memory leaks)") {
SUBCASE("Second token not identifier") { SUBCASE("Second token not identifier") {
test_failing_let_parsing("let 5 = 5;", {token::type::IDENTIFIER}); test_failing_parsing("let 5 = 5;", {token::type::IDENTIFIER});
} }
SUBCASE("Third token not '='") { SUBCASE("Third token not '='") {
test_failing_let_parsing("let five ! 5;", {token::type::ASSIGN}); test_failing_parsing("let five ! 5;", {token::type::ASSIGN});
} }
SUBCASE("Missing both identifier and '='") { SUBCASE("Missing both identifier and '='") {
test_failing_let_parsing("let 5;", {token::type::IDENTIFIER}); test_failing_parsing("let 5;", {token::type::IDENTIFIER});
} }
SUBCASE("Multiple parsing errors") { SUBCASE("Multiple parsing errors") {
test_failing_let_parsing( test_failing_parsing(
"let 5; let ! = 5; let five = 5; let five 5; let;", "let 5; let ! = 5; let five = 5; let five 5; let;",
{token::type::IDENTIFIER, {token::type::IDENTIFIER,
token::type::IDENTIFIER, token::type::IDENTIFIER,

View File

@@ -87,3 +87,41 @@ void test_infix_expression(
CHECK(op_exp->op == op); CHECK(op_exp->op == op);
test_literal_expression(op_exp->right, right); test_literal_expression(op_exp->right, right);
} }
void test_failing_parsing(
std::string input_s,
std::vector<token::type> expected_types,
int n_good_statements
) {
std::stringstream input(input_s);
lexer::lexer l{input};
parser::parser p{l};
std::unique_ptr<ast::program> program = p.parse_program();
// Check for errors
REQUIRE(p.errors.size() >= expected_types.size());
// ^^ because even though you were thinking
// about a specific token to be there, other `expect_next -> false` might be
// triggered for subexpressions due to the first one
int i = 0;
for (auto& t : expected_types) {
ast::error::expected_next* en =
cast<ast::error::expected_next>(p.errors[i++]);
REQUIRE(en->expected_type == t);
}
// normal program check
REQUIRE_MESSAGE(
program != nullptr,
"parse_program() returned a null pointer"
);
REQUIRE(program->statements.size() >= n_good_statements);
// ^^ because even though you were thinking
// about a specific number of statements to be there, it failing for
// `expect_next` might trigger a sub-expression to be triggered correctly
// and be parsed as the expression_stmt
}

View File

@@ -67,3 +67,4 @@ void test_integer_literal(ast::expression*, int);
void test_boolean_literal(ast::expression*, bool); void test_boolean_literal(ast::expression*, bool);
void test_literal_expression(ast::expression*, std::any&); void test_literal_expression(ast::expression*, std::any&);
void test_infix_expression(ast::expression*, std::any, std::string, std::any); void test_infix_expression(ast::expression*, std::any, std::string, std::any);
void test_failing_parsing(std::string, std::vector<token::type>, int = 0);