#ifndef CODEINSTRUCTIONS_H
#define CODEINSTRUCTIONS_H

#include "llvmlayer.h"
#include "ast.h"
#include <llvm/IR/Value.h>
#include <vector>
#include "pass/compilepass.h"

namespace xreate {
    namespace containers {

class Iterator{
public :
    virtual llvm::Value* begin() =0;
    virtual llvm::Value* end() = 0;
    virtual llvm::Value* get(llvm::Value* index,const std::string& hintRetVar="") = 0;
    virtual llvm::Value* move(llvm::Value* index, const std::string& hintRetVar="")=0;
    virtual ~Iterator(){};

    static Iterator* create(CompilePass::Context context, const Symbol& var);
};

class Instructions {
public:
    Instructions(CompilePass::Context ctx);
    llvm::Value* compileArrayIndex(const Symbol &dataSymbol, std::vector<llvm::Value *> indexes, std::string ident = "");
    llvm::Value* compileStructIndex(llvm::Value* aggregate, const ExpandedType& t, const std::string& idx);
        /*
        *    - map Computation -> Llvm_Array: Prohibited, we do not know a result size
        *    - map Llvm_Array -> Computation: considered in `compileGetElement`
        *    - map Llvm_Array -> Llvm_Array considered by this method
        */
    llvm::Value*compileMapSolid(const Expression &expr, const std::string hintRetVar = "");
    llvm::Value* compileFold(const Expression& fold, const std::string& ident="");
    llvm::Value* compileIf(const Expression& exprIf, const std::string& ident);
    llvm::Value* compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar);
    llvm::Value* compileConstantStringAsPChar(const string &data, const std::string& hintRetVar);
    llvm::Value* compileConstantArray(const Expression &expr, const std::string&  hintRetVar="");

private:
    CompilePass::Context context;
    llvm::IntegerType* const tyNum;
};



    }}

#endif //CODEINSTRUCTIONS_H

/*
    template<Operator Instruction>
    struct InstructionClasses {};

    template<>
    struct InstructionClasses<Operator::LIST> {
        typedef InstructionList Impl;
    };

    template<>
    struct InstructionClasses<Operator::MAP> {
        typedef InstructionMap Impl;
    };

    template<Operator Instruction>
    class CodeInstruction: public InstructionClasses<Instruction>::Impl
    {
        typedef  typename InstructionClasses<Instruction>::Impl InstructionImpl;

    public:
        CodeInstruction(CodeScope* parent)
                : InstructionImpl(parent)
        {}

        llvm::Value *
        compileExpression(const Expression &expr, LLVMLayer &l, const std::string * const hintRetVar)
        {
            if (expr.op == Instruction)
                return InstructionImpl::compileDefault(expr, l, hintRetVar);

            return CodeScope::compileExpression(expr, l, hintRetVar);
        }
    };
}
*/
