#include "cfgpass.h"
#include <QString>

using namespace std;

CFGPass::CFGPass(const AST& entity)
    : __root(entity)
{

}

void
CFGPass::process(const Expression& entity, const FID funcId)
{
    switch(entity.__state)
    {
        case Expression::COMPOUND:
            for (const Expression& op: entity.operands)
            {
                process(op, funcId);
            }

            if (entity.__op == Operator::CALL)
            {
                const std::string& calleeName = entity.__valueS;
                assert(__root.__indexFunctions.count(calleeName));
                FID calleeId = __root.__indexFunctions.at(calleeName);

                if (!__graph.existsNode(calleeId))
                {
                    __graph.addNode(calleeId, string(calleeName));
                    process(calleeId);
                }

                __graph.addLink(funcId, calleeId);
            }
        break;

        case Expression::IDENT:
            const Function& func = __root.getFunctionById(funcId);
            const std::string& identName = entity.__valueS;

            assert(func.__vartable.count(identName));
            VID identId = func.__vartable.at(identName);

            if (func.__declarations.count(identId))
            {
                const Expression& identExpr = func.__declarations.at(identId);
                process(identExpr, funcId);
            }
    }
}

void
CFGPass::process(const FID funcId)
{
    const Function& f = __root.getFunctionById(funcId);
    process(f.__body, funcId);
}

void
CFGPass::run(ClaspLayer& clasp)
{
    __graph = CFGraph();
    cout << "CFGPass::run" << endl;

    for(FID f=0, fcount=__root.getFunctionsCount(); f<fcount; ++f)
    {
        const Function& func = __root.getFunctionById(f);
        __graph.addNode(f, string(func.getName()));
        process(f);
    }

    clasp.addCFGData(std::move(__graph));
}
