#include "abstractpass.h"
#include "attachments.h"
using namespace std;

namespace xreate {
    void
    AbstractPass::process(ManagedRulePtr rule)
    {}

    void
    AbstractPass::process(ManagedFnPtr function) {
        PassContext context;
        context.function = function;

        process(function->getEntryScope(), context);
    }

    void
    AbstractPass::process(CodeScope *scope, PassContext context) {
        context.scope = scope;
        process(scope->__body, context);
    }

    void
    AbstractPass::process(const Expression& expression, PassContext context, const std::string& varDecl){
        switch (expression.__state) {
            case Expression::COMPOUND:
            for (const Expression &op: expression.getOperands()) {
                process(op, context);
            }

            assert(expression.op != Operator::MAP || expression.op == Operator::MAP && expression.blocks.size());
            for (ManagedScpPtr scope: expression.blocks) {
                process(&*scope, context);
            }

                /*
            if (expression.op == Operator::CALL) {
                const std::string &calleeName = expression.getValueString();
                ManagedFnPtr callee = root->findFunction(calleeName);
            }
                */
            break;

            case Expression::IDENT:
                assert(context.scope);

                string ident = expression.getValueString();
                const Symbol& symbol = context.scope->findSymbol(ident, *man->llvm);

                if (SymbolAttachments::get<IsDeclVisited> (symbol, false)) {break;}
                SymbolAttachments::put<IsDeclVisited> (symbol, true);

                PassContext context2 = context;
                context2.scope = symbol.scope;
                if (CodeScope::hasDeclaration(symbol)) {
                    process(CodeScope::findDeclaration(symbol), context2, ident);
                }

                break;
        }
    }

    void
    AbstractPass::processFnCall(ManagedFnPtr function, PassContext context)
    {
    }

    void
    AbstractPass::run() {
        ManagedRulePtr rule = man->root->begin<MetaRuleAbstract>();
        while (rule.isValid()) {
            process(rule);
            ++rule;
        }

        ManagedFnPtr f = man->root->begin<Function>();
        while (f.isValid()) {
            process(f);
            ++f;
        }
    }

    void AbstractPass::finish()
    {}

    AbstractPass::AbstractPass(PassManager *manager)
            : man(manager) {
    }
}