#include "Parsodus/lrtables/generator.h"
#include "Parsodus/lrtables/LR1Itemset.h"
#include "Parsodus/lrtables/LALR1Itemset.h"
#include "Parsodus/util/symbols.h"
#include "gtest/gtest.h"

#include <memory>

TEST(lr1, only) {
    using namespace pds;
    using namespace pds::lr;

	Grammar grammar;
	grammar.start = "s";
	grammar.variables = {"s","a","b"};
	grammar.terminals = {"A", "B"};

    for (const std::pair<std::string, std::vector<std::string>>& p : std::initializer_list<std::pair<std::string, std::vector<std::string>>>({
                {"s", {"B", "a", "A"}},
                {"s", {"b", "A"}},
                {"s", {"a"}},
                {"s", {"B", "b"}},
                {"a", {"A"}},
                {"b", {"A"}}
            })) {

        grammar.rules.emplace_back(std::make_shared<Rule>(p.first, p.second));
    }

    {
        Generator<LR1Itemset> g(grammar);
        LRTable table;
        ASSERT_NO_THROW(table = g.generate());
        std::vector<std::map<std::string, std::pair<Action, std::size_t>>> act = {
            {
                {"A", {Action::SHIFT, 1}},
                {"B", {Action::SHIFT, 2}}
            }, {
                {util::EOF_PLACEHOLDER, {Action::REDUCE, 4}},
                {"A", {Action::REDUCE, 5}}
            }, {
                {"A", {Action::SHIFT, 6}}
            }, {
                {util::EOF_PLACEHOLDER, {Action::REDUCE, 2}}
            }, {
                {"A", {Action::SHIFT, 9}}
            }, {
                {util::EOF_PLACEHOLDER, {Action::ACCEPT, 0}}
            }, {
                {util::EOF_PLACEHOLDER, {Action::REDUCE, 5}},
                {"A", {Action::REDUCE, 4}}
            }, {
                {"A", {Action::SHIFT, 10}}
            }, {
                {util::EOF_PLACEHOLDER, {Action::REDUCE, 3}}
            }, {
                {util::EOF_PLACEHOLDER, {Action::REDUCE, 1}}
            }, {
                {util::EOF_PLACEHOLDER, {Action::REDUCE, 0}}
            }
        };
        ASSERT_EQ(act.size(), table.act.size());
        for (std::size_t i = 0; i < act.size(); i++) {
            EXPECT_EQ(act[i], table.act[i]);
        }

        std::vector<std::map<std::string, size_t>> got = {
            { {"s", 5}, {"a", 3}, {"b", 4} },
            {},
            { {"a", 7}, {"b", 8} },
            {},
            {},
            {},
            {},
            {},
            {},
            {},
            {}
        };
        ASSERT_EQ(got.size(), table.goto_.size());
        for (std::size_t i = 0; i < got.size(); i++) {
            EXPECT_EQ(got[i], table.goto_[i]);
        }
    }

    {
        pds::lr::Generator<pds::lr::LALR1Itemset> g(grammar);
        ASSERT_THROW(g.generate(), std::runtime_error);
    }
}