#ifndef COMPILEPASS_H
#define COMPILEPASS_H

#include "abstractpass.h"
#include "llvm/IR/Function.h"

namespace xreate {



class CompilePass : public AbstractPass<void>
{
public:

        class CodeScopeUnit;
        class FunctionUnit{
        public:
           FunctionUnit(ManagedFnPtr f, CompilePass* p)
            : function(f), pass(p) {}

           llvm::Value* compileInline(std::vector<llvm::Value*>&& args, CompilePass::FunctionUnit* outer);
           bool isInline();
           llvm::Function* compile();

           CodeScopeUnit* getEntry();
           CodeScopeUnit* getScopeUnit(CodeScope* scope);
           CodeScopeUnit* getScopeUnit(ManagedScpPtr scope);

           ManagedFnPtr function;
           llvm::Function* raw = nullptr;
        private:
           CompilePass* pass;
           std::map<CodeScope*, std::unique_ptr<CodeScopeUnit>> scopes;
        };

        class CodeScopeUnit {
        public:
            CodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass);

            void bindArg(llvm::Value* var, std::string&& name);
            std::map<VID,llvm::Value*> __rawVars;

            llvm::Value* compile(const std::string& hintBlockDecl="");
            llvm::Value* compileSymbol(const Symbol& s, std::string hintRetVar="");
            llvm::Value* process(const Expression& expr, const std::string& hintVarDecl="");
            CodeScope* scope;

        private:
            CompilePass* pass;
            llvm::Value* raw = nullptr;
            FunctionUnit* function;

            llvm::Value* convertType(llvm::Value* source, llvm::Type* tyTarget);
        };

        struct Context{
            FunctionUnit* function;
            CodeScopeUnit* scope;
            CompilePass* pass;
        };

        struct FunctionQuery{
            FunctionQuery(std::string&& functionName): name(functionName) {}

            std::string name;
        };

    CompilePass(PassManager* manager): AbstractPass<void>(manager) {}
    FunctionUnit* getFunctionUnit(const FunctionQuery& f);
    void run() override;
    llvm::Function* getEntryFunction();

private:
    std::map<Function*, std::unique_ptr<FunctionUnit>> functions;
    llvm::Function* entry = 0;


};

}

#endif // COMPILEPASS_H
