/* 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 "ast.h"
#include "utils.h"

#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Target/TargetOptions.h"

namespace llvm {
  class ExecutionEngine;
}

namespace xreate {

class ExternLayer;

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

  mutable llvm::LLVMContext llvmContext;
  llvm::IRBuilder<> irBuilder;
  AST *ast = 0;
  ExternLayer *layerExtern =0;
  std::unique_ptr<llvm::Module> module;
  std::unique_ptr<llvm::ExecutionEngine> jit;
  llvm::TargetOptions optsTarget;
  llvm::CodeGenOpt::Level optsLevel = llvm::CodeGenOpt::None;

  void moveToGarbage(void *o);
  llvm::Type* toLLVMType(const Expanded<TypeAnnotation>& ty, const Expression& expr = Expression());
  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;
};

class TypesHelper {
public:
  bool isArrayT(const Expanded<TypeAnnotation>& ty);
  bool isRecordT(const Expanded<TypeAnnotation>& ty);
  bool isPointerT(const Expanded<TypeAnnotation>& ty);
  bool isIntegerT(const Expanded<TypeAnnotation>& ty);
  llvm::IntegerType* getPreferredIntTy() const;
  std::vector<std::string> getRecordFields(const Expanded<TypeAnnotation>& t);

  TypesHelper(const LLVMLayer* llvmlayer): llvm(llvmlayer){}

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