#ifndef PARTIAL_APPLIER_H
#define PARTIAL_APPLIER_H
#include "llvm/Type.h"
#include "llvm/Value.h"
#include "llvm/Function.h"
#include "llvm/Module.h"
#include "llvm/LLVMContext.h"

#include <vector>
#include <tr1/memory>

class PartialApplier
{
public:
        struct ArgInfo
        {
                unsigned index; // -1U for value
                union {
                        llvm::Type * type;
                        llvm::Value * value;
                } arg;
                bool signedp;

                ArgInfo (unsigned index_, 
                         llvm::Type * type_,
                         bool signedp_)
                        : index(index_),
                          signedp(signedp_)
                {
                        arg.type = type_;
                };

                ArgInfo (unsigned index_, 
                         llvm::Value * value_,
                         bool signedp_)
                        : index(index_),
                          signedp(signedp_)
                {
                        arg.value = value_;
                };
        };

private:
        llvm::LLVMContext * context;
        llvm::Function * function;
        llvm::FunctionType * ftype;
        std::vector<ArgInfo> args;
        unsigned runtime_arg_count; //
public:
        PartialApplier (llvm::Function * function);

        void addValue(llvm::Value *, bool signedp = true);
        void addIntValue(uint64_t value,
                         unsigned bits = 32,
                         bool signedp = false);
        void addSIntValue(int64_t value,
                          unsigned bits = 32);
        void addUIntValue(uint64_t value,
                          unsigned bits = 32);


        void addArg(unsigned index = -1, llvm::Type * type = 0,
                    bool signedp = true);

        llvm::Function * apply(const std::string &name,
                               llvm::Module * module = 0,
                               bool vararg = false);
};
#endif

