Only the function name needs to be passed in and not the full signature. The implementation will append the appropriate (_,_,...) part making it at build time.
180 lines
6.2 KiB
C++
180 lines
6.2 KiB
C++
#pragma once
|
|
|
|
#include "vm.hpp"
|
|
#include "string_bt.hpp"
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <vector>
|
|
#include <type_traits>
|
|
|
|
namespace wren {
|
|
typedef std::tuple<const char*, const char*> ModuleAndName;
|
|
|
|
namespace detail {
|
|
#if __cpp_concepts >= 201907
|
|
template <typename T>
|
|
concept ConstCharTuple = requires {
|
|
std::same_as<std::remove_cv_t<T>, Handle> or
|
|
std::same_as<std::remove_cv_t<T>, ModuleAndName>;
|
|
};
|
|
#endif
|
|
} //namespace detail
|
|
|
|
#if __cpp_concepts >= 201907
|
|
template <typename... Outs, detail::ConstCharTuple... Params>
|
|
#else
|
|
template <typename... Outs, typename... Params>
|
|
#endif
|
|
std::tuple<Outs...> variables(VM& vm, Params&&... modules_names);
|
|
|
|
template <typename R, typename... Args>
|
|
R call (VM& vm, const Handle& object, const Handle& method, const Args&... args);
|
|
|
|
template <typename R, typename... Args>
|
|
R call (VM& vm, const ModuleAndName& object, const Handle& method, const Args&... args);
|
|
|
|
template <typename R, std::size_t N, typename... Args>
|
|
R call (VM& vm, const ModuleAndName& object, const char (&method)[N], const Args&... args);
|
|
|
|
void interpret (VM& vm, const std::string& module_name, const std::string& script);
|
|
void set (VM& vm, int slot_num, const char* value);
|
|
void set (VM& vm, int slot_num, double value);
|
|
void set (VM& vm, int slot_num, bool value);
|
|
void set (VM& vm, int slot_num, std::nullptr_t);
|
|
void set (VM& vm, int slot_num, const char* bytes, std::size_t length);
|
|
void set (VM& vm, int slot_num, const std::string& value);
|
|
void set (VM& vm, int slot_num, std::string_view value);
|
|
void set (VM& vm, int slot_num, const std::vector<char>& value);
|
|
void set (VM& vm, int slot_num, const char* beg, const char* end);
|
|
void set (VM& vm, int slot_num, int value);
|
|
std::string_view slot_string_view (VM& vm, int slot_num);
|
|
template <typename T> T get (VM& vm, int slot_num);
|
|
void variable(VM& vm, const ModuleAndName& mod_and_name, int slot);
|
|
void variable(VM& vm, const Handle& handle, int slot);
|
|
|
|
namespace detail {
|
|
#if __cpp_concepts >= 201907
|
|
template <typename... Outs, int... Indices, ConstCharTuple... Params>
|
|
#else
|
|
template <typename... Outs, int... Indices, typename... Params>
|
|
#endif
|
|
inline std::tuple<Outs...> variables_impl (
|
|
VM& vm,
|
|
std::integer_sequence<int, Indices...>,
|
|
Params&&... modules_names
|
|
) {
|
|
if constexpr (sizeof...(Outs) == 0) {
|
|
return {};
|
|
}
|
|
else {
|
|
static_assert(sizeof...(Params) == sizeof...(Outs), "Expected a module/name pair per requested output");
|
|
static_assert(sizeof...(Outs) == sizeof...(Indices), "Mismatching index count");
|
|
|
|
vm.ensure_slots(sizeof...(Params));
|
|
(variable(vm, modules_names, Indices), ...);
|
|
return std::tuple<Outs...>(get<Outs>(vm, Indices)...);
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
inline void set_single_for_call (VM& vm, int slot, const T& value) {
|
|
set(vm, slot, value);
|
|
}
|
|
|
|
template <>
|
|
inline void set_single_for_call (VM& vm, int slot_num, const Handle& handle) {
|
|
vm.set_slot_handle(handle, slot_num);
|
|
}
|
|
|
|
template <>
|
|
inline void set_single_for_call (VM& vm, int slot_num, const ModuleAndName& name) {
|
|
variable(vm, name, slot_num);
|
|
}
|
|
|
|
template <typename... Args, int... Indices>
|
|
inline void set_for_call (std::integer_sequence<int, Indices...>, VM& vm, const Args&... args) {
|
|
vm.ensure_slots(sizeof...(Args));
|
|
(set_single_for_call(vm, Indices + 1, args), ...);
|
|
}
|
|
} //namespace detail
|
|
|
|
#if __cpp_concepts >= 201907
|
|
template <typename... Outs, detail::ConstCharTuple... Params>
|
|
#else
|
|
template <typename... Outs, typename... Params>
|
|
#endif
|
|
inline std::tuple<Outs...> variables(VM& vm, Params&&... modules_names) {
|
|
return detail::variables_impl<Outs...>(vm, std::make_integer_sequence<int, sizeof...(Outs)>(), std::forward<Params>(modules_names)...);
|
|
}
|
|
|
|
inline void interpret (VM& vm, const std::string& module_name, const std::string& script) {
|
|
return vm.interpret(module_name.c_str(), script.c_str());
|
|
}
|
|
|
|
inline void set (VM& vm, int slot_num, const char* value) {
|
|
vm.set_slot_string(slot_num, value);
|
|
}
|
|
|
|
inline void set (VM& vm, int slot_num, double value) {
|
|
vm.set_slot_double(slot_num, value);
|
|
}
|
|
|
|
inline void set (VM& vm, int slot_num, bool value) {
|
|
vm.set_slot_bool(slot_num, value);
|
|
}
|
|
|
|
inline void set (VM& vm, int slot_num, std::nullptr_t) {
|
|
vm.set_slot_null(slot_num);
|
|
}
|
|
|
|
inline void set (VM& vm, int slot_num, const char* bytes, std::size_t length) {
|
|
vm.set_slot_bytes(slot_num, bytes, length);
|
|
}
|
|
|
|
inline void set (VM& vm, int slot_num, const std::string& value) {
|
|
vm.set_slot_string(slot_num, value.c_str());
|
|
}
|
|
|
|
inline void set (VM& vm, int slot_num, std::string_view value) {
|
|
vm.set_slot_bytes(slot_num, value.data(), value.size());
|
|
}
|
|
|
|
inline void set (VM& vm, int slot_num, const std::vector<char>& value) {
|
|
vm.set_slot_bytes(slot_num, value.data(), value.size());
|
|
}
|
|
|
|
inline void set (VM& vm, int slot_num, int value) {
|
|
vm.set_slot_double(slot_num, static_cast<double>(value));
|
|
}
|
|
|
|
template <typename R, typename... Args>
|
|
inline R call (VM& vm, const Handle& object, const Handle& method, const Args&... args) {
|
|
detail::set_for_call<Args...>(std::make_integer_sequence<int, sizeof...(Args)>(), vm, args...);
|
|
vm.call(method);
|
|
if constexpr (not std::is_same<void, R>::value) {
|
|
return get<R>(vm, 0);
|
|
}
|
|
}
|
|
|
|
template <typename R, typename... Args>
|
|
inline R call (VM& vm, const ModuleAndName& object, const Handle& method, const Args&... args) {
|
|
vm.ensure_slots(sizeof...(args) + 1);
|
|
variable(vm, object, 0);
|
|
Handle obj_handle = vm.slot_handle(0);
|
|
return call<R, Args...>(vm, obj_handle, method, args...);
|
|
}
|
|
|
|
template <typename R, std::size_t N, typename... Args>
|
|
inline R call (VM& vm, const ModuleAndName& object, const char (&method)[N], const Args&... args) {
|
|
const constexpr char dummy_name_buff[N] = {0};
|
|
const constexpr auto params = dhandy::bt::string<N, char>(dummy_name_buff) +
|
|
dhandy::bt::make_string("(") +
|
|
((static_cast<void>(args), dhandy::bt::make_string(",_")) + ...).template substr<1>() +
|
|
dhandy::bt::make_string(")");
|
|
;
|
|
char cat_buff[params.size() + 1];
|
|
std::copy(method, method + N - 1, cat_buff);
|
|
std::copy(params.data() + N - 1, params.data() + params.size() + 1, cat_buff + N - 1);
|
|
return call<R, Args...>(vm, object, vm.make_call_handle(cat_buff), args...);
|
|
}
|
|
} //namespace wren
|