/*
 * versionspass.cpp
 *
 * Author: pgess <v.melnychenko@xreate.org>
 * Created on January 4, 2017, 3:13 PM
 */

#include "versionspass.h"
#include "ast.h"
#include "abstractpass.h"

namespace xreate {

Symbol
getNextVersion(const Symbol& s){
    return Symbol{ScopedSymbol{s.identifier.id, s.identifier.version+1}, s.scope};
}

void
applyDependentUpperBound(const Symbol& symbol, const list<Symbol>& dependancies){
    for (const Symbol& right: dependencies){
        auto rightEnd = right.getNextVersion();

        VersionInferiorsList&  infs = Attachments::get<VersionInferiorsList>(rightEnd);
        infs.push_back(left);
    }
}

std::list<Symbol>
VersionsPass::process(const Expression& expression, PassContext context, const std::string& varDecl = ""){
    if (expression.__state == Expression::COMPOUND){
        std::list<Symbol> resultDependencies;

        for (const Expression &op: expression.getOperands()) {
            std::list<Symbol> deps = process(op, context);

            resultDependencies.insert(std::inserter(resultDependencies, resultDependencies.end()),
                    deps.begin(), deps.end());
        }

        for (CodeScope* scope: expression.blocks) {
            std::list<Symbol> deps = process(scope, context);

            resultDependencies.insert(std::inserter(resultDependencies, resultDependencies.end()),
                    deps.begin(), deps.end());
        }

        return resultDependencies;
    }

    if (expression.__state == Expression::IDENT){
        const Symbol symb = Attachments::get<Symbol>(expression);
        processSymbol(symb, context, expression.getValueString());

        return {symb};
    }

    return {};
}

void
VersionsPass::processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol){
    enum {MODE_ALIAS, MODE_COPY } mode = MODE_ALIAS;

    const Expression& declaration = CodeScope::findDeclaration(symbol);

    if (declaration.op == Operator::CALL_INTRINSIC){
        if (declaration.getValueString() == "copy"){
            mode = MODE_COPY;
        }
    }

    if (symbol.identifier.version != VERSION_NONE){
        mode = MODE_COPY;
    }

    std::list<Symbol> dependencies = process(declaration);

    switch (mode) {
        case MODE_COPY: applyDependentUpperBound(left, dependencies); break;
        case MODE_ALIAS: applyDependentUpperBound(left.getNextVersion(), dependencies); break;
    }
}

}