extracted and abstracted function
This commit is contained in:
@@ -1,14 +1,10 @@
|
||||
#include "ast/statements/let.hpp"
|
||||
|
||||
#include "ast/ast.hpp"
|
||||
#include "ast/errors/error.hpp"
|
||||
#include "lexer/lexer.hpp"
|
||||
#include "parser/parser.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
#include <doctest.h>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
void test_let_statement(ast::statement* stmt, const std::string name) {
|
||||
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);
|
||||
}
|
||||
|
||||
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_CASE("Malformed let statement (checking for memory leaks)") {
|
||||
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 '='") {
|
||||
test_failing_let_parsing("let five ! 5;", {token::type::ASSIGN});
|
||||
test_failing_parsing("let five ! 5;", {token::type::ASSIGN});
|
||||
}
|
||||
|
||||
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") {
|
||||
test_failing_let_parsing(
|
||||
test_failing_parsing(
|
||||
"let 5; let ! = 5; let five = 5; let five 5; let;",
|
||||
{token::type::IDENTIFIER,
|
||||
token::type::IDENTIFIER,
|
||||
|
@@ -87,3 +87,41 @@ void test_infix_expression(
|
||||
CHECK(op_exp->op == op);
|
||||
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
|
||||
}
|
||||
|
@@ -67,3 +67,4 @@ void test_integer_literal(ast::expression*, int);
|
||||
void test_boolean_literal(ast::expression*, bool);
|
||||
void test_literal_expression(ast::expression*, 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);
|
||||
|
Reference in New Issue
Block a user