#include "../../extern/doctest.hpp"
#include "../../src/Parser/Parser.hpp"

using namespace MalachScript;

#define PARSER_TEST(name, tokens, asserts)                                                                             \
    TEST_CASE(name) {                                                                                                  \
        std::vector<Parser::LexToken*> vec = {                                                                         \
            tokens,                                                                                                    \
            new Parser::LexTokenImpl<Parser::LexTokenKind::EndOfFile>(TextSpan(0, 0)),                                 \
        };                                                                                                             \
        for (size_t i = 0; i < vec.size() - 1; i++) {                                                                  \
            vec[i]->SetNext(vec[i + 1]);                                                                               \
        }                                                                                                              \
        Diagnostics::Diagnostics diags;                                                                                \
        auto parser = Parser::Parser(u8"scriptname", vec.front(), &diags);                                             \
        auto* script = parser.Parse();                                                                                 \
        REQUIRE(diags.GetMessages().empty());                                                                          \
        asserts;                                                                                                       \
        delete vec[0];                                                                                                 \
        delete script;                                                                                                 \
    }

#define PARSER_TEST_TOKENS(...) __VA_ARGS__

PARSER_TEST("Parse basic class without body",
            PARSER_TEST_TOKENS(new Parser::LexTokenImpl<Parser::LexTokenKind::ClassKeyword>(TextSpan(0, 0)),
                               new Parser::IdentifierToken(TextSpan(0, 0), u8"foobar"),
                               new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0))),
            {
                REQUIRE(script->GetStatements().size() == 1);
                REQUIRE(script->GetStatements()[0].get()->GetKind() == Parser::ParsedStatementKind::Class);
            })

PARSER_TEST("Parse basic class without body with whitespaces",
            PARSER_TEST_TOKENS(new Parser::LexTokenImpl<Parser::LexTokenKind::ClassKeyword>(TextSpan(0, 0)),
                               new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)),
                               new Parser::IdentifierToken(TextSpan(0, 0), u8"foobar"),
                               new Parser::LexTokenImpl<Parser::LexTokenKind::Whitespace>(TextSpan(0, 0)),
                               new Parser::LexTokenImpl<Parser::LexTokenKind::SemicolonSymbol>(TextSpan(0, 0))),
            {
                REQUIRE(script->GetStatements().size() == 1);
                REQUIRE(script->GetStatements()[0].get()->GetKind() == Parser::ParsedStatementKind::Class);
            })

PARSER_TEST(
    "Parse basic class with empty body",
    PARSER_TEST_TOKENS(new Parser::LexTokenImpl<Parser::LexTokenKind::ClassKeyword>(TextSpan(0, 0)),
                       new Parser::IdentifierToken(TextSpan(0, 0), u8"foobar"),
                       new Parser::LexTokenImpl<Parser::LexTokenKind::OpenCurlyParenthesisSymbol>(TextSpan(0, 0)),
                       new Parser::LexTokenImpl<Parser::LexTokenKind::CloseCurlyParenthesisSymbol>(TextSpan(0, 0))),
    {
        REQUIRE(script->GetStatements().size() == 1);
        REQUIRE(script->GetStatements()[0].get()->GetKind() == Parser::ParsedStatementKind::Class);
    })