diff --git a/examples/calendar/main.cpp b/examples/calendar/main.cpp index ce05c68..b8f6ef1 100644 --- a/examples/calendar/main.cpp +++ b/examples/calendar/main.cpp @@ -120,9 +120,10 @@ int main() { MyConf conf; wren::VM vm(&conf, nullptr); - vm.callback_manager().add_callback(true, "calendar", "Calendar", "today()", &Calendar::today) - .add_callback(false, "calendar", "Calendar", "add_appointment(_)", wren::make_method_bindable<&Calendar::add_appointment>()) - .add_callback(false, "calendar", "Calendar", "appointment_count()", wren::make_method_bindable<&Calendar::appointment_count>()); + vm.callback_manager() + .add_callback(true, "calendar", "Calendar", "today()", [](){return &Calendar::today;}) + .add_callback(false, "calendar", "Calendar", "add_appointment(_)", wren::make_function_bindable<&Calendar::add_appointment>) + .add_callback(false, "calendar", "Calendar", "appointment_count()", wren::make_function_bindable<&Calendar::appointment_count>); vm.class_manager().add_class_maker("calendar", "Calendar", wren::make_foreign_class); vm.interpret("main", g_test_script); diff --git a/examples/dieroll/main.cpp b/examples/dieroll/main.cpp index fdd6b5c..a22e701 100644 --- a/examples/dieroll/main.cpp +++ b/examples/dieroll/main.cpp @@ -65,8 +65,8 @@ int main() { wren::DefConfiguration config; wren::VM vm(&config, &custom_data); - vm.callback_manager().add_callback(true, "main", "Game", "user_input()", &user_input) - .add_callback(true, "main", "Game", "random()", &random_num); + vm.callback_manager().add_callback(true, "main", "Game", "user_input()", [](){return &user_input;}) + .add_callback(true, "main", "Game", "random()", [](){return &random_num;}); interpret(vm, "main", load_file("main.wren")); wren::call(vm, wren::MN<"main", "the_game">, "play_game"); diff --git a/examples/greet/main.cpp b/examples/greet/main.cpp index 085e982..a9bb14e 100644 --- a/examples/greet/main.cpp +++ b/examples/greet/main.cpp @@ -66,7 +66,7 @@ int main() { wren::DefConfiguration config; wren::VM vm(&config, nullptr); - vm.callback_manager().add_callback(true, "main", "User", "get_env(_)", &user_get_env); + vm.callback_manager().add_callback(true, "main", "User", "get_env(_)", [](){return &user_get_env;}); vm.interpret("main", g_script); diff --git a/examples/math_vector/main.cpp b/examples/math_vector/main.cpp index 5648035..742f491 100644 --- a/examples/math_vector/main.cpp +++ b/examples/math_vector/main.cpp @@ -37,6 +37,8 @@ namespace { foreign x=(value) foreign y=(value) foreign z=(value) + + foreign static base_x() } )script"}; @@ -53,6 +55,10 @@ vec3.x = 3.5 vec3.y = vec2.x / vec2.z vec3.z = vec1.x + vec2.y / 4.0 System.print("vec3 modified by scripting: <%(vec3.x), %(vec3.y), %(vec3.z)>") + +var vec_base_x = MathVector.base_x() +System.print("vec_base_x modified by scripting: <%(vec_base_x.x), %(vec_base_x.y), %(vec_base_x.z)>") + )script"; template @@ -74,6 +80,8 @@ System.print("vec3 modified by scripting: <%(vec3.x), %(vec3.y), %(vec3.z)>") void set_y(T y) { m_y = y; } void set_z(T z) { m_z = z; } + static Vector base_x() { return {1.0, 0.0, 0.0}; } + private: T m_x{}, m_y{}, m_z{}; }; @@ -98,18 +106,19 @@ System.print("vec3 modified by scripting: <%(vec3.x), %(vec3.y), %(vec3.z)>") } //unnamed namespace int main() { - using wren::make_method_bindable; + using wren::make_function_bindable; using wren::make_foreign_class; MyConf conf; wren::VM vm(&conf, nullptr); vm.callback_manager() - .add_callback(false, "math_vector", "MathVector", "x=(_)", make_method_bindable<&Vector::set_x>()) - .add_callback(false, "math_vector", "MathVector", "y=(_)", make_method_bindable<&Vector::set_y>()) - .add_callback(false, "math_vector", "MathVector", "z=(_)", make_method_bindable<&Vector::set_z>()) - .add_callback(false, "math_vector", "MathVector", "x", make_method_bindable<&Vector::x>()) - .add_callback(false, "math_vector", "MathVector", "y", make_method_bindable<&Vector::y>()) - .add_callback(false, "math_vector", "MathVector", "z", make_method_bindable<&Vector::z>()); + .add_callback(false, "math_vector", "MathVector", "x=(_)", make_function_bindable<&Vector::set_x>) + .add_callback(false, "math_vector", "MathVector", "y=(_)", make_function_bindable<&Vector::set_y>) + .add_callback(false, "math_vector", "MathVector", "z=(_)", make_function_bindable<&Vector::set_z>) + .add_callback(false, "math_vector", "MathVector", "x", make_function_bindable<&Vector::x>) + .add_callback(false, "math_vector", "MathVector", "y", make_function_bindable<&Vector::y>) + .add_callback(false, "math_vector", "MathVector", "z", make_function_bindable<&Vector::z>) + .add_callback(true, "math_vector", "MathVector", "base_x()", make_function_bindable<&Vector::base_x>); vm.class_manager() .add_class_maker("math_vector", "MathVector", make_foreign_class, diff --git a/include/wrenpp/callback_manager.hpp b/include/wrenpp/callback_manager.hpp index 74db076..fc2c33c 100644 --- a/include/wrenpp/callback_manager.hpp +++ b/include/wrenpp/callback_manager.hpp @@ -23,6 +23,7 @@ #include #include #include +#include namespace wren::detail { class FullSignatureOwning; @@ -106,7 +107,13 @@ namespace wren { CallbackManager(); ~CallbackManager() noexcept; - CallbackManager& add_callback (bool is_static, std::string_view module_name, std::string_view class_name, std::string_view signature, foreign_method_t cb); + CallbackManager& add_callback ( + bool is_static, + std::string_view module_name, + std::string_view class_name, + std::string_view signature, + std::function make_cb + ); foreign_method_t callback (bool is_static, std::string_view module_name, std::string_view class_name, std::string_view signature) const; private: diff --git a/include/wrenpp/vm_fun.hpp b/include/wrenpp/vm_fun.hpp index e7ce3a0..98768a6 100644 --- a/include/wrenpp/vm_fun.hpp +++ b/include/wrenpp/vm_fun.hpp @@ -53,9 +53,6 @@ namespace wren { T* make_wren_object(VM& vm, Args&&... args); #endif - template - foreign_method_t make_method_bindable(); - void interpret (VM& vm, const std::string& module_name, const std::string& script); void variable(VM& vm, ModuleAndName mod_and_name, int slot); void variable(VM& vm, const Handle& handle, int slot); @@ -87,23 +84,59 @@ namespace wren { (set_single_for_call(vm, Indices + 1, args), ...); } - template struct MakeMethodBindableConstNonConst { - private: + template + class CallImplemProvider; + template + class CallImplemProvider { + protected: + typedef R return_type; + static constexpr std::size_t argument_count = sizeof...(Args); + template static R call_implem (std::integer_sequence, VM& vm) { static_assert(sizeof...(Indices) == sizeof...(Args), "Mismatching argument count"); T* obj = foreign(vm, 0); return (obj->*Method)(get>(vm, Indices + 1)...); } + }; + template + class CallImplemProvider { + protected: + typedef R return_type; + static constexpr std::size_t argument_count = sizeof...(Args); - public: - static foreign_method_t make() { - return [](VM& vm, ModuleAndName) { + template + static R call_implem (std::integer_sequence, VM& vm) { + static_assert(sizeof...(Indices) == sizeof...(Args), "Mismatching argument count"); + T* obj = foreign(vm, 0); + return (obj->*ConstMethod)(get>(vm, Indices + 1)...); + } + }; + template + class CallImplemProvider { + protected: + typedef R return_type; + static constexpr std::size_t argument_count = sizeof...(Args); + + template + static R call_implem (std::integer_sequence, VM& vm) { + static_assert(sizeof...(Indices) == sizeof...(Args), "Mismatching argument count"); + return (*Function)(get>(vm, Indices + 1)...); + } + }; + + template + struct MakeFunctionBindable : private CallImplemProvider { + foreign_method_t operator()() const { + using R = typename CallImplemProvider::return_type; + constexpr int argument_count = static_cast(CallImplemProvider::argument_count); + + return [](VM& vm, ModuleAndName mn) { if constexpr (std::is_same_v) { - call_implem(std::make_integer_sequence(), vm); + CallImplemProvider::call_implem(std::make_integer_sequence(), vm); } else { - auto ret = call_implem(std::make_integer_sequence(), vm); + auto ret = CallImplemProvider::call_implem(std::make_integer_sequence(), vm); //TODO: check for errors vm.ensure_slots(1); if constexpr (std::is_fundamental::value) { @@ -112,24 +145,29 @@ namespace wren { else { ModuleAndName wren_name = wren_class_name_from_type(vm); R* const new_object = make_wren_object(vm, wren_name, std::move(ret)); + static_cast(new_object); } } }; } }; - template struct MakeMethodBindable; - template struct MakeMethodBindable { - static foreign_method_t make() { - return [](VM& vm, ModuleAndName) { + template struct MakeFunctionBindable { + foreign_method_t operator()() const { + return [](VM& vm, ModuleAndName mn) { T* obj = foreign(vm, 0); - (obj->*Method)(vm); + (obj->*Method)(vm, mn); }; } }; - template struct MakeMethodBindable : MakeMethodBindableConstNonConst {}; - template struct MakeMethodBindable : MakeMethodBindableConstNonConst {}; + template struct MakeFunctionBindable { + foreign_method_t operator()() const { + return [](VM& vm, ModuleAndName mn) { + (*Function)(vm, mn); + }; + } + }; } //namespace detail inline void interpret (VM& vm, const std::string& module_name, const std::string& script) { @@ -198,7 +236,5 @@ namespace wren { #endif template - inline foreign_method_t make_method_bindable() { - return detail::MakeMethodBindable::make(); - } + constexpr detail::MakeFunctionBindable make_function_bindable; } //namespace wren diff --git a/src/callback_manager.cpp b/src/callback_manager.cpp index 01bca7f..1f5b715 100644 --- a/src/callback_manager.cpp +++ b/src/callback_manager.cpp @@ -59,16 +59,22 @@ namespace wren { CallbackManager::CallbackManager() = default; CallbackManager::~CallbackManager() noexcept = default; - CallbackManager& CallbackManager::add_callback (bool is_static, std::string_view module_name, std::string_view class_name, std::string_view signature, foreign_method_t cb) { + CallbackManager& CallbackManager::add_callback ( + bool is_static, + std::string_view module_name, + std::string_view class_name, + std::string_view signature, + std::function make_cb + ) { using detail::FullSignatureOwning; using detail::TempFullSignature; MethodMap& map = *method_map(is_static); auto it_found = map.find(TempFullSignature{module_name, class_name, signature}); if (map.cend() == it_found) - map.insert(it_found, std::make_pair(FullSignatureOwning{module_name, class_name, signature}, cb)); + map.insert(it_found, std::make_pair(FullSignatureOwning{module_name, class_name, signature}, make_cb())); else - it_found->second = cb; + it_found->second = make_cb(); return *this; }