extracted to a function the casting of the

different types to make tests cleaner
This commit is contained in:
Karma Riuk
2025-07-09 11:06:28 +02:00
parent 79b1aeb45f
commit c65cefe867
4 changed files with 98 additions and 54 deletions

View File

@@ -1,5 +1,6 @@
#include "ast/expressions/identifier.hpp" #include "ast/expressions/identifier.hpp"
#include "ast/expressions/integer.hpp" #include "ast/expressions/integer.hpp"
#include "ast/expressions/prefix.hpp"
#include "utils.hpp" #include "utils.hpp"
#include <doctest.h> #include <doctest.h>
@@ -11,24 +12,11 @@ TEST_SUITE("Parser: expression") {
) { ) {
setup("foobar;"); setup("foobar;");
REQUIRE(program->statements.size() == 1); REQUIRE(program->statements.size() == 1);
ast::expression_stmt* expression_stmt; ast::expression_stmt* expression_stmt =
REQUIRE_NOTHROW( cast<ast::expression_stmt>(program->statements[0]);
expression_stmt =
dynamic_cast<ast::expression_stmt*>(program->statements[0])
);
REQUIRE_MESSAGE(
expression_stmt != nullptr,
"Couldn't cast statement to an expression statement"
);
ast::identifier* ident; ast::identifier* ident =
REQUIRE_NOTHROW( cast<ast::identifier>(expression_stmt->expression);
ident = dynamic_cast<ast::identifier*>(expression_stmt->expression)
);
REQUIRE_MESSAGE(
ident != nullptr,
"Couldn't cast expression to an identifier"
);
REQUIRE(ident->value == "foobar"); REQUIRE(ident->value == "foobar");
REQUIRE(ident->token_literal() == "foobar"); REQUIRE(ident->token_literal() == "foobar");
@@ -40,27 +28,61 @@ TEST_SUITE("Parser: expression") {
) { ) {
setup("5;"); setup("5;");
REQUIRE(program->statements.size() == 1); REQUIRE(program->statements.size() == 1);
ast::expression_stmt* expression_stmt;
REQUIRE_NOTHROW(
expression_stmt =
dynamic_cast<ast::expression_stmt*>(program->statements[0])
);
REQUIRE_MESSAGE(
expression_stmt != nullptr,
"Couldn't cast statement to an expression statement"
);
ast::integer_literal* int_lit; ast::expression_stmt* expression_stmt =
REQUIRE_NOTHROW( cast<ast::expression_stmt>(program->statements[0]);
int_lit =
dynamic_cast<ast::integer_literal*>(expression_stmt->expression) ast::integer_literal* int_lit =
); cast<ast::integer_literal>(expression_stmt->expression);
REQUIRE_MESSAGE(
int_lit != nullptr,
"Couldn't cast expression to an identifier"
);
REQUIRE(int_lit->value == 5); REQUIRE(int_lit->value == 5);
REQUIRE(int_lit->token_literal() == "5"); REQUIRE(int_lit->token_literal() == "5");
}; };
// TEST_CASE_FIXTURE(
// ParserFixture,
// "Simple expression statement with prefix before integer"
// ) {
// SUBCASE("Prefix: '!'") {
// setup("!5;");
//
// REQUIRE(program->statements.size() == 1);
// ast::expression_stmt* expression_stmt =
// cast<ast::expression_stmt>(program->statements[0]);
//
// ast::prefix_expr* prefix_expr;
// REQUIRE_NOTHROW(
// prefix_expr =
// dynamic_cast<ast::prefix_expr*>(expression_stmt->expression)
// );
// REQUIRE_MESSAGE(
// prefix_expr != nullptr,
// "Couldn't cast expression to an identifier"
// );
//
// REQUIRE(prefix_expr->value == 5);
// REQUIRE(prefix_expr->token_literal() == "5");
// }
// SUBCASE("Prefix: '-'") {
// setup("-15;");
//
// REQUIRE(program->statements.size() == 1);
// ast::expression_stmt* expression_stmt =
// get_expression_stmt(program->statements[0]);
//
// ast::integer_literal* int_lit;
// REQUIRE_NOTHROW(
// int_lit = dynamic_cast<ast::integer_literal*>(
// expression_stmt->expression
// )
// );
// REQUIRE_MESSAGE(
// int_lit != nullptr,
// "Couldn't cast expression to an identifier"
// );
//
// REQUIRE(int_lit->value == 5);
// REQUIRE(int_lit->token_literal() == "5");
// }
// }
} }

View File

@@ -1,6 +1,7 @@
#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 "lexer/lexer.hpp"
#include "parser/parser.hpp" #include "parser/parser.hpp"
#include "utils.hpp" #include "utils.hpp"
@@ -10,12 +11,7 @@
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");
ast::let_stmt* let_stmt; ast::let_stmt* let_stmt = cast<ast::let_stmt>(stmt);
REQUIRE_NOTHROW(let_stmt = dynamic_cast<ast::let_stmt*>(stmt));
REQUIRE_MESSAGE(
let_stmt != nullptr,
"Couldn't cast statement to a let statement"
);
REQUIRE(let_stmt->name->value == name); REQUIRE(let_stmt->name->value == name);
REQUIRE(let_stmt->name->token_literal() == name); REQUIRE(let_stmt->name->token_literal() == name);
@@ -38,13 +34,8 @@ void test_failing_let_parsing(
int i = 0; int i = 0;
for (auto& e : p.errors) { for (auto& e : p.errors) {
ast::error::expected_next* en; ast::error::expected_next* en = cast<ast::error::expected_next>(e);
REQUIRE_NOTHROW(en = dynamic_cast<ast::error::expected_next*>(e));
REQUIRE_MESSAGE(
en != nullptr,
"Couldn't cast the error to an 'expected_next'"
);
REQUIRE(en->expected_type == expected_types[i++]); REQUIRE(en->expected_type == expected_types[i++]);
} }

View File

@@ -14,12 +14,7 @@ return 103213;\
for (const auto stmt : program->statements) { for (const auto stmt : program->statements) {
REQUIRE(stmt->token_literal() == "return"); REQUIRE(stmt->token_literal() == "return");
ast::return_stmt* let_stmt; ast::return_stmt* return_stmt = cast<ast::return_stmt>(stmt);
REQUIRE_NOTHROW(let_stmt = dynamic_cast<ast::return_stmt*>(stmt));
REQUIRE_MESSAGE(
let_stmt != nullptr,
"Couldn't cast statement to a return statement"
);
} }
} }
} }

View File

@@ -1,9 +1,45 @@
#include "ast/ast.hpp"
#include "lexer/lexer.hpp" #include "lexer/lexer.hpp"
#include "parser/parser.hpp" #include "parser/parser.hpp"
#include <doctest.h>
#include <sstream> #include <sstream>
void check_parser_errors(const std::vector<ast::error::error*>& errors); void check_parser_errors(const std::vector<ast::error::error*>&);
namespace {
template <typename T, typename Base>
T* cast_impl(Base* base) {
static_assert(
std::is_base_of_v<Base, T>,
"T must be derived from Base"
);
T* t;
REQUIRE_NOTHROW(t = dynamic_cast<T*>(base));
REQUIRE_MESSAGE(
t != nullptr,
"Couldn't cast expression to a " * std::string(typeid(T).name())
);
return t;
}
} // namespace
// Overloads for your known base types
template <typename T>
T* cast(ast::expression* expr) {
return cast_impl<T, ast::expression>(expr);
}
template <typename T>
T* cast(ast::statement* stmt) {
return cast_impl<T, ast::statement>(stmt);
}
template <typename T>
T* cast(ast::error::error* err) {
return cast_impl<T, ast::error::error>(err);
}
struct ParserFixture { struct ParserFixture {
std::stringstream input; std::stringstream input;