/*
 * testsCFG.cpp
 *
 *  Created on: Jul 17, 2015
 *      Author: pgess
 */

#include "xreatemanager.h"
#include "pass/dfapass.h"
#include "pass/cfapass.h"

#include "analysis/DominatorsTreeAnalysisProvider.h"

#include "gtest/gtest.h"

#include <boost/scoped_ptr.hpp>
#include <boost/smart_ptr/scoped_array.hpp>

using namespace xreate;
using namespace std;

TEST(CFA, testFunctionAnnotationsClasp){
    string&& program =
        "f2 = function::int; annotationF2 {\n"
        "    0\n"
        "}\n"
        "\n"
        "f1 = function:: int; entry; annotationF1 {\n"
        "    f2() + 10\n"
        "}";


    details::tier1::XreateManager* man = details::tier1::XreateManager::prepare(move(program));
    man->analyse();

    ClaspLayer::ModelFragment answer = man->clasp->query("annotationF1");
    int countNoneValue = 0;
    if (answer) countNoneValue = std::distance(answer->first, answer->second);
    EXPECT_EQ(1, countNoneValue);

    answer = man->clasp->query("annotationF2");
    countNoneValue = 0;
    if (answer) countNoneValue = std::distance(answer->first, answer->second);

    EXPECT_EQ(1, countNoneValue);
}

TEST(CFA, testLoopContextExists){
    details::tier1::XreateManager* man = details::tier1::XreateManager::prepare (
        "interface(cfa){\n"
        "    operator fold:: annotation1.\n"
        "}\n"
        "\n"
        "main = function:: int; entry {\n"
        "    x = [1..10]:: [int].\n"
        "    sum = loop fold (x->el:: int, 0->sum):: int {\n"
        "        el + sum + f1()\n"
        "    }.  \n"
        "    sum\n"
        "}"
        "case context:: annotation1 {"
        " f1 = function::int {\n"
        "  	x = 0:: int.		 "
        "       x\n"
        " }"
        "}"
    );

    man->analyse();
    ClaspLayer::ModelFragment model = man->clasp->query("annotation1");
    ScopePacked scopeIdActual = std::get<0>(ClaspLayer::parse<ScopePacked>(model->first->second));

    CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope();
    const Expression& exprSum = scopeEntry->getDeclaration(scopeEntry->getSymbol("sum"));
    CodeScope* scopeExpected = exprSum.blocks.front();

    ScopePacked scopeIdExpected = man->clasp->pack(scopeExpected);
    ASSERT_EQ(scopeIdExpected, scopeIdActual);
}

TEST(CFA, CFGRoots){
    std::string program =
R"CODE(
    main = function::int{a()+ b()}
    a= function::int {c1() + c2()}
    b= function::int {c2()}
    c1=function::int{0}
    c2=function::int{0}
)CODE";

    boost::scoped_ptr<XreateManager> manager
        (XreateManager::prepare(move(program)));

    manager->registerPass(new CFAPass(manager.get()) , PassId::CFGPass);
    manager->executePasses();
    manager->clasp->run();

    DominatorsTreeAnalysisProvider domProvider;
    domProvider.run(manager->clasp);

    DominatorsTreeAnalysisProvider::Dominators expectedFDom= {
         {0, {0, 9}}
        ,{1, {1, 4}}
        ,{2, {7, 8}}
        ,{3, {2, 3}}
        ,{4, {5, 6}}
    };

    DominatorsTreeAnalysisProvider::Dominators expectedPostDom= {
         {0, {5, 6}}
        ,{1, {3, 4}}
        ,{2, {8, 9}}
        ,{3, {1, 2}}
        ,{4, {7, 10}}
    };

    ASSERT_EQ(expectedFDom, domProvider.getForwardDominators());
    ASSERT_EQ(expectedPostDom, domProvider.getPostDominators());
}
