Add support for object parameters to Wren calls

This commit is contained in:
King_DuckZ 2024-05-25 01:47:51 +02:00
commit 05298b6111
9 changed files with 282 additions and 37 deletions

View file

@ -0,0 +1,63 @@
/* Copyright 2020-2024, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Wrenpp is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with wrenpp. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "wrenpp/handle.hpp"
#include <utility>
namespace wren {
template <typename T>
class ForeignObject {
public:
ForeignObject() = default;
ForeignObject (std::nullptr_t) : ForeignObject() {}
ForeignObject (T* obj, Handle&& handle);
~ForeignObject() noexcept = default;
void set_to_slot (int num);
T& object() { return *m_object; }
const T& object() const { return *m_object; }
Handle& handle() { return m_handle; }
const Handle& handle() const { return m_handle; }
bool is_valid() const { return nullptr != m_object; }
operator T&() { return object(); }
operator const T&() const { return object(); }
operator Handle&() { return handle(); }
operator const Handle&() const { return handle(); }
bool operator!= (std::nullptr_t) const { return nullptr != m_object; }
bool operator== (std::nullptr_t) const { return nullptr == m_object; }
private:
Handle m_handle;
T* m_object{nullptr};
};
template <typename T>
inline ForeignObject<T>::ForeignObject (T* obj, Handle&& handle) :
m_handle(std::move(handle)),
m_object(obj)
{ }
template <typename T>
inline void ForeignObject<T>::set_to_slot (int num) {
m_handle.set_to_slot(num);
}
} //namespace wren

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2022, Michele Santullo
/* Copyright 2020-2024, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify
@ -18,6 +18,7 @@
#pragma once
#include "../vm.hpp"
#include "../handle.hpp"
#include "module_and_name.hpp"
#include <string_view>
#include <vector>
@ -87,6 +88,8 @@ namespace wren {
void set (VM& vm, int slot_num, const char* beg, const char* end);
void set (VM& vm, int slot_num, int value);
void set (VM& vm, int slot_num, std::size_t value);
void set (VM& vm, int slot_num, const Handle& handle);
void set (VM& vm, int slot_num, const ModuleAndName& name);
std::string_view slot_string_view (VM& vm, int slot_num);
template <typename T> detail::GetTypeToRetType_t<T> get (VM& vm, int slot_num);
template <typename T> T* foreign (VM& vm, int slot_num);
@ -138,6 +141,14 @@ namespace wren {
vm.set_slot_double(slot_num, static_cast<double>(value));
}
inline void set (VM& vm, int slot_num, const Handle& handle) {
vm.set_slot_handle(handle, slot_num);
}
inline void set (VM& vm, int slot_num, const ModuleAndName& name) {
vm.variable_or_throw(name.module_name_char(), name.class_name_char(), slot_num);
}
template <typename T>
inline T* foreign (VM& vm, int slot_num) {
T* obj = static_cast<T*>(vm.slot_foreign(slot_num));

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2022, Michele Santullo
/* Copyright 2020-2024, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify
@ -42,6 +42,8 @@ namespace wren {
operator WrenHandle*() const { return m_handle; }
operator bool() const { return nullptr != m_handle; }
void set_to_slot (int num);
private:
WrenHandle* m_handle;
VM* m_vm;

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2022, Michele Santullo
/* Copyright 2020-2024, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify
@ -26,6 +26,7 @@
#include "detail/construct_foreign_class.hpp"
#include "detail/setters_getters.hpp"
#include "detail/wren_class_name_from_type.hpp"
#include "detail/foreign_object.hpp"
#include <string>
#include <string_view>
#include <type_traits>
@ -46,11 +47,11 @@ namespace wren {
R call (VM& vm, ModuleAndName object, const char (&method)[N], const Args&... args);
template <typename T, typename... Args>
T* make_wren_object(VM& vm, ModuleAndName mn, Args&&... args);
ForeignObject<T> make_wren_object(VM& vm, ModuleAndName mn, Args&&... args);
#if defined(WRENPP_WITH_NAME_GUESSING)
template <typename T, dhandy::bt::string Mod, typename... Args>
T* make_wren_object(VM& vm, Args&&... args);
ForeignObject<T> make_wren_object(VM& vm, Args&&... args);
#endif
void interpret (VM& vm, const std::string& module_name, const std::string& script);
@ -61,28 +62,13 @@ namespace wren {
void abort_fiber_with_error (VM& vm, int slot, std::string_view message);
namespace detail {
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);
}
//Sets arguments so wren is ready to perform a function call. It doesn't
//touch at slot 0, so eventual objects for method calls must be set
//manually
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), ...);
(set(vm, Indices + 1, args), ...);
}
template <auto V>
@ -145,7 +131,7 @@ namespace wren {
}
else {
ModuleAndName wren_name = wren_class_name_from_type<R>(vm);
R* const new_object = make_wren_object<R>(vm, wren_name, std::move(ret));
ForeignObject<R> new_object = make_wren_object<R>(vm, wren_name, std::move(ret));
static_cast<void>(new_object);
}
}
@ -197,15 +183,13 @@ namespace wren {
inline R call (VM& vm, const Handle& object, const char (&method)[N], const Args&... args) {
using dhandy::bt::string;
const constexpr char dummy_name_buff[N] = {0};
const constexpr auto params = string<N, char>(dummy_name_buff) +
string("(") +
const constexpr auto params = string("(") +
((static_cast<void>(args), string(",_")) + ... + string("")).template substr<1>() +
string(")");
;
char cat_buff[params.size() + 1];
char cat_buff[params.size() + 1 + N - 1];
std::copy(method, method + N - 1, cat_buff);
std::copy(params.data() + N - 1, params.data() + params.size() + 1, cat_buff + N - 1);
std::copy(params.data(), params.data() + params.size() + 1, cat_buff + N - 1);
return call<R, Args...>(vm, object, vm.make_call_handle(cat_buff), args...);
}
@ -218,12 +202,12 @@ namespace wren {
}
template <typename T, typename... Args>
inline T* make_wren_object(VM& vm, ModuleAndName mn, Args&&... args) {
variable(vm, mn, 0);
inline ForeignObject<T> make_wren_object(VM& vm, ModuleAndName mn, Args&&... args) {
variable_ensure_slot(vm, mn, 0);
void* const mem = vm.set_slot_new_foreign(0, 0, sizeof(T));
try {
T* const obj = new(mem) T{std::forward<Args>(args)...};
return obj;
return {obj, vm.slot_handle(0)};
}
catch (const std::runtime_error& err) {
abort_fiber_with_error(vm, 1, err.what());
@ -233,7 +217,7 @@ namespace wren {
#if defined(WRENPP_WITH_NAME_GUESSING)
template <typename T, dhandy::bt::string Mod, typename... Args>
inline T* make_wren_object(VM& vm, Args&&... args) {
inline ForeignObject<T> make_wren_object(VM& vm, Args&&... args) {
return make_wren_object<T>(
vm,
MN<Mod, g_guessed_class_name<T>>,