/* 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/.
 * 
 * File:   targetstatic.h
 * Author: pgess  <v.melnychenko@xreate.org>
 *
 * Created on July 2, 2016, 1:25 PM
 */

#ifndef TARGETSTATIC_H
#define TARGETSTATIC_H

#include "ast.h"
#include "pass/compilepass.h"
#include "compilation/targets.h"
#include "pass/interpretationpass.h"
#include "clasplayer.h"

namespace xreate{ namespace interpretation{
    class TargetInterpretation;
    class InterpretationScope;
    class InterpretationFunction;
}}

namespace xreate{ namespace compilation{
    template <>
    struct TargetInfo<interpretation::TargetInterpretation> {
        typedef Expression Result;
        typedef interpretation::InterpretationScope Scope;
        typedef interpretation::InterpretationFunction Function;
    };    
}}

namespace xreate{ namespace interpretation{
    
    /** \brief Encapsulates interpretation of a single Code Scope */
class InterpretationScope: public  compilation::Scope<TargetInterpretation>{
    typedef Scope<TargetInterpretation> Parent;
    
public:
    InterpretationScope(CodeScope* scope, compilation::Function<TargetInterpretation>* f): Parent(scope, f) {}
    Expression process(const Expression& expression) override;
    
    llvm::Value* compile(const Expression& expression, const compilation::Context& context);
    
private:
    llvm::Value* compileHybrid(const InterpretationOperator& op, const Expression& expression, const compilation::Context& context);
    //llvm::Value* compilePartialFnCall(const Expression& expression, const Context& context);
    
    CodeScope* processOperatorIf(const Expression& expression);
    CodeScope* processOperatorSwitch(const Expression& expression);
    CodeScope* processOperatorSwitchVariant(const Expression& expression);
};

/** \brief Encapsulates interpretation of a single %Function */
class InterpretationFunction: public compilation::Function<TargetInterpretation>{
public:
    InterpretationFunction(const ManagedFnPtr& function, compilation::Target<TargetInterpretation>* target);
    Expression process(const std::vector<Expression>& args);
};

/** \brief Signature of a partially interpreted function */
struct PIFSignature{
    ManagedFnPtr declaration;
    std::vector<Expression> bindings;
};

class PIFunctionUnit;

/** \brief Partially interpreted function */
class PIFunction: public InterpretationFunction{
public:
    PIFunctionUnit* functionUnit;
    PIFSignature signatureInstance;
    
    PIFunction(PIFSignature&& sig, size_t id, TargetInterpretation* target);
    llvm::Function* compile();
};

bool operator<(const PIFSignature& lhs, PIFunction* const rhs);
bool operator<(PIFunction* const lhs, const PIFSignature& rhs);

/** \brief Encapsulates actual [Interpretation](/w/concepts/dfa) based on InterpretationPass analysis results */
class TargetInterpretation: public compilation::Target<TargetInterpretation>{
public:    
    TargetInterpretation(AST* root, CompilePass* passCompilation): Target<TargetInterpretation>(root), pass(passCompilation){}

        //target:
public:
   InterpretationFunction* getFunction(compilation::IFunctionUnit* unit);
   PIFunction* getFunction(PIFSignature&& sig);
   
private:
   std::map<PIFSignature, PIFunction*> __pifunctions;
   std::map<compilation::IFunctionUnit*, InterpretationFunction*> __dictFunctionsByUnit;

        //self:
public:
    CompilePass* pass;
    llvm::Value* compile(const Expression& expression, const compilation::Context& ctx);
private:
    InterpretationScope* transformContext(const compilation::Context& c);
};

/**\brief Interpretation-aware Code Scope decorator
 * \extends xreate::compilation::ICodeScopeUnit
 */
template<class Parent>
class InterpretationScopeDecorator: public Parent{
public:
    InterpretationScopeDecorator(CodeScope* codeScope, compilation::IFunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){}
    
    virtual llvm::Value* process(const Expression& expr, const std::string& hintVarDecl){
        const InterpretationData& data = Attachments::get<InterpretationData>(expr, {ANY, NONE});
        bool flagInterpretationEligible = (data.resolution == INTR_ONLY || data.op != InterpretationOperator::NONE);

        if (flagInterpretationEligible){
            compilation::Context ctx{this, this->function, this->pass};
            return Parent::pass->targetInterpretation->compile(expr, ctx);
        }
        
        return Parent::process(expr, hintVarDecl);
    }
};

/** \brief translates Logic expression(Gringo::Symbol) into Xreate expression to support intrinsic function `query` */
Expression representAsAnnotation(const Gringo::Symbol& symbol);

}} //end of xreate:: interpretation

#endif /* TARGETSTATIC_H */


//transformers: 
//    template<> 
//    struct TransformerInfo<TargetInterpretation> {
//        static const int id = 1;
//    };
