/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/*
 * Author: pgess <v.melnychenko@xreate.org>
 * Created on July 9, 2018, 6:04 PM
 */

#include "compilation/polymorph.h"
using namespace std;

namespace xreate{
namespace polymorph{

PolymorphFnInvocation::PolymorphFnInvocation(const latereasoning::LateAnnotation& selector,
                                             std::list<ManagedFnPtr> calleeSpecializations,
                                             CompilePass* pass,
                                             PolymorphQuery* query,
                                             LLVMLayer* llvm,
                                             latereasoning::LateReasoningCompiler* compiler)
: __selector(selector), __calleeSpecializations(calleeSpecializations),
__pass(pass), __query(query), __llvm(llvm), __compiler(compiler) { }

llvm::Value*
PolymorphFnInvocation::operator()(std::vector<llvm::Value *>&& args, const std::string& hintDecl) {
    std::map<Selector, ManagedFnPtr> dictSelectors;
    for(ManagedFnPtr specialization : __calleeSpecializations) {
        dictSelectors.emplace(specialization->guard, specialization);
    }

    compilation::IFunctionUnit* specAny = __pass->getFunctionUnit(__calleeSpecializations.front());
    return __compiler->compileAutoExpand(
        __selector,
        specAny->prepareResult(),
        hintDecl,
        [this, &args, hintDecl, &dictSelectors](const Gringo::Symbol & selectorRaw) {
            const Expression & selectorE = __query->getValue(selectorRaw);
            assert(dictSelectors.count(selectorE) && "Inappropriate specialization guard");
            compilation::BruteFnInvocation* invoc = new compilation::BruteFnInvocation(
                __pass->getFunctionUnit(dictSelectors.at(selectorE))->compile(),
                __llvm);

            return invoc->operator()(move(args), hintDecl);
        });
}
}
}
