/* 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/.
 * 
 * llvmlayer.h
 *
 *      Author: pgess <v.melnychenko@xreate.org>
 */

#ifndef LLVMLAYER_H
#define LLVMLAYER_H

#include "llvm/IR/Module.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "utils.h"

namespace xreate {

class AST;
class ExternLayer;
class TypeAnnotation;

/** \brief A wrapper over LLVM toolchain to generate and execute bytecode */
class LLVMLayer {
public:
    LLVMLayer(AST* rootAST);

    mutable llvm::LLVMContext llvmContext;
    llvm::IRBuilder<> builder;
    AST *ast = 0;
    ExternLayer *layerExtern =0;
    std::unique_ptr<llvm::Module> module;
    std::unique_ptr<llvm::ExecutionEngine> jit;


    void moveToGarbage(void *o);

    llvm::Type* toLLVMType(const Expanded<TypeAnnotation>& ty) const;
    void print();
    void* getFunctionPointer(llvm::Function* function);

    void initJit();
    
private:
    llvm::Type* toLLVMType(const Expanded<TypeAnnotation>& ty, std::map<int, llvm::StructType*>& conjunctions) const;
    std::vector<void *> __garbage;
};

struct TypeUtils {
    bool isStruct(const Expanded<TypeAnnotation>& ty);
    bool isPointer(const Expanded<TypeAnnotation>& ty);
    std::vector<std::string> getStructFields(const Expanded<TypeAnnotation>& t);

    TypeUtils(LLVMLayer*llvmlayer)
        : llvm(llvmlayer){}

    private:
        LLVMLayer* llvm;
};
    
}
#endif // LLVMLAYER_H
