Skip to content

File functionFactory.h

File List > jac > machine > functionFactory.h

Go to the documentation of this file

#pragma once

#include <functional>

#include "class.h"
#include "funcUtil.h"
#include "values.h"


namespace jac {

class FunctionFactory {

    ContextRef _context;

    template<typename Func, typename Res, typename... Args>
    inline Function newFunctionHelper(Func& func, std::function<Res(Args...)>);

    template<typename Func, typename Res>
    inline Function newFunctionVariadicHelper(Func& func, std::function<Res(std::vector<ValueWeak>)>);

    template<typename Func, typename Res, typename... Args>
    inline Function newFunctionThisHelper(Func& func, std::function<Res(ContextRef, ValueWeak, Args...)>);

    template<typename Func, typename Res>
    inline Function newFunctionThisVariadicHelper(Func& func, std::function<Res(ContextRef, ValueWeak, std::vector<ValueWeak>)>);
public:
    FunctionFactory(ContextRef context) : _context(context) {}

    template<class Func>
    Function newFunction(Func func) {
        return newFunctionHelper(func, std::function(func));
    }

    template<class Func>
    Function newFunctionVariadic(Func func) {
        return newFunctionVariadicHelper(func, std::function(func));
    }

    template<class Func>
    Function newFunctionThis(Func func) {
        return newFunctionThisHelper(func, std::function(func));
    }

    template<class Func>
    Function newFunctionThisVariadic(Func func) {
        return newFunctionThisVariadicHelper(func, std::function(func));
    }
};


template<typename Func, typename Res, typename... Args>
inline Function FunctionFactory::newFunctionHelper(Func& func, std::function<Res(Args...)>) {
    Func* funcPtr = new Func(std::move(func));

    struct FuncProtoBuilder : public ProtoBuilder::Opaque<Func>, public ProtoBuilder::Callable {
        static Value callFunction(ContextRef ctx, ValueWeak funcObj, ValueWeak thisVal, std::vector<ValueWeak> args) {
            Func* ptr = ProtoBuilder::Opaque<Func>::getOpaque(ctx, funcObj);
            return processCall<Func, Res, Args...>(ctx, thisVal, args, *ptr);
        }
    };

    using FuncClass = Class<FuncProtoBuilder>;
    FuncClass::init("CppFunction");

    return static_cast<Value>(FuncClass::createInstance(_context, funcPtr)).to<Function>();
}

template<class Func, typename Res>
Function FunctionFactory::newFunctionVariadicHelper(Func& func, std::function<Res(std::vector<ValueWeak>)>) {
    Func* funcPtr = new Func(std::move(func));

    struct FuncProtoBuilder : public ProtoBuilder::Opaque<Func>, public ProtoBuilder::Callable {
        static Value callFunction(ContextRef ctx, ValueWeak funcObj, ValueWeak thisVal, std::vector<ValueWeak> args) {
            Func* ptr = ProtoBuilder::Opaque<Func>::getOpaque(ctx, funcObj);
            return processCallVariadic<Func, Res>(ctx, thisVal, args, *ptr);
        }
    };

    using FuncClass = Class<FuncProtoBuilder>;
    FuncClass::init("CppFunction");

    return static_cast<Value>(FuncClass::createInstance(_context, funcPtr)).to<Function>();
}

template<typename Func, typename Res, typename... Args>
Function FunctionFactory::newFunctionThisHelper(Func& func, std::function<Res(ContextRef, ValueWeak, Args...)>) {
    Func* funcPtr = new Func(std::move(func));

    struct FuncProtoBuilder : public ProtoBuilder::Opaque<Func>, public ProtoBuilder::Callable {
        static Value callFunction(ContextRef ctx, ValueWeak funcObj, ValueWeak thisVal, std::vector<ValueWeak> args) {
            Func* ptr = ProtoBuilder::Opaque<Func>::getOpaque(ctx, funcObj);
            return processCallThis<Func, Res, Args...>(ctx, thisVal, args, *ptr);
        }
    };

    using FuncClass = Class<FuncProtoBuilder>;
    FuncClass::init("CppFunction");

    return static_cast<Value>(FuncClass::createInstance(_context, funcPtr)).to<Function>();
}

template<typename Func, typename Res>
Function FunctionFactory::newFunctionThisVariadicHelper(Func& func, std::function<Res(ContextRef, ValueWeak, std::vector<ValueWeak>)>) {
    Func* funcPtr = new Func(std::move(func));

    struct FuncProtoBuilder : public ProtoBuilder::Opaque<Func>, public ProtoBuilder::Callable {
        static Value callFunction(ContextRef ctx, ValueWeak funcObj, ValueWeak thisVal, std::vector<ValueWeak> args) {
            Func* ptr = ProtoBuilder::Opaque<Func>::getOpaque(ctx, funcObj);
            return processCallThisVariadic<Func, Res>(ctx, thisVal, args, *ptr);
        }
    };

    using FuncClass = Class<FuncProtoBuilder>;
    FuncClass::init("CppFunction");

    return static_cast<Value>(FuncClass::createInstance(_context, funcPtr)).to<Function>();
}


} // namespace jac