233 lines
8.4 KiB
C++
233 lines
8.4 KiB
C++
/* Copyright 2020-2022, 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 "detail/has_method.hpp"
|
|
#include "detail/error_type.hpp"
|
|
#include "detail/StringCRC32.hpp"
|
|
#include "detail/wren_types.hpp"
|
|
#include "handle.hpp"
|
|
#include <memory>
|
|
#include <tuple>
|
|
#include <utility>
|
|
#if __cpp_concepts >= 201907
|
|
# include <concepts>
|
|
#endif
|
|
#include <cstdint>
|
|
#include <stdexcept>
|
|
|
|
namespace wren {
|
|
class Configuration;
|
|
class VM;
|
|
class DynafuncMaker;
|
|
class CallbackManager;
|
|
class ClassManager;
|
|
|
|
enum class SlotType {
|
|
Bool, Num, Foreign, List, Null, String, Unknown, Map
|
|
};
|
|
|
|
namespace detail {
|
|
struct Callbacks {
|
|
void (*write_fn)(Configuration&, VM*, wren_string_t) {nullptr};
|
|
void (*error_fn)(Configuration&, VM*, ErrorType, wren_string_t, int, wren_string_t) {nullptr};
|
|
void* (*reallocate_fn)(void*, std::size_t) {nullptr};
|
|
const char* (*resolve_module_fn)(Configuration&, VM*, wren_string_t, wren_string_t) {nullptr};
|
|
char* (*load_module_fn)(Configuration&, VM*, wren_string_t) {nullptr};
|
|
foreign_method_t (*foreign_method_fn)(Configuration&, VM*, wren_string_t, wren_string_t, bool, wren_string_t) {nullptr};
|
|
foreign_class_t (*foreign_class_fn)(Configuration&, VM*, wren_string_t, wren_string_t) {nullptr};
|
|
void (*load_module_complete_fn)(Configuration&, VM*, wren_string_t, char*) {nullptr};
|
|
|
|
Configuration* config_obj {nullptr};
|
|
VM* owner {nullptr};
|
|
DynafuncMaker* dynafunc {nullptr};
|
|
};
|
|
} //namespace detail
|
|
|
|
class VM {
|
|
public:
|
|
template <typename T, typename U> VM (T* conf, U* user_data);
|
|
template <typename T> VM (T* conf, std::nullptr_t);
|
|
VM (const VM&) = delete;
|
|
VM (VM&& other) = default;
|
|
~VM() noexcept;
|
|
|
|
VM& operator= (VM&&) = default;
|
|
|
|
void interpret (const char* module_name, const char* script);
|
|
void call (const Handle& method);
|
|
void release_handle (Handle& handle) noexcept;
|
|
void ensure_slots(int num_slots);
|
|
int slot_count();
|
|
void variable(const char* module, const char* name, int slot) noexcept;
|
|
void variable_or_throw(const char* module, const char* name, int slot);
|
|
void set_slot_handle(const Handle& handle, int slot);
|
|
SlotType slot_type(int slot_num);
|
|
Handle slot_handle(int slot_num);
|
|
Handle make_call_handle(const char* signature);
|
|
|
|
//slot setters
|
|
void set_slot_string (int slot_num, const char* value);
|
|
void set_slot_double (int slot_num, double value);
|
|
void set_slot_bool (int slot_num, bool value);
|
|
void set_slot_null (int slot_num);
|
|
void set_slot_bytes (int slot_num, const char* bytes, std::size_t length);
|
|
void* set_slot_new_foreign (int slot_num, int class_slot, std::size_t size);
|
|
|
|
//slot getters
|
|
const char* slot_string (int slot_num);
|
|
double slot_double (int slot_num);
|
|
bool slot_bool (int slot_num);
|
|
std::pair<const char*, int> slot_bytes (int slot_num);
|
|
void* slot_foreign (int slot_num);
|
|
|
|
template <typename U> U* user_data();
|
|
template <typename U> void set_user_data (U* user_data);
|
|
void set_user_data (std::nullptr_t);
|
|
bool has_user_data() const noexcept;
|
|
bool has_module (const char* module) const noexcept;
|
|
bool has_variable (const char* module, const char* name) const noexcept;
|
|
|
|
void abort_fiber(int slot_num);
|
|
|
|
std::size_t dynafunc_byte_size() const;
|
|
void reset (Configuration* conf);
|
|
|
|
CallbackManager& callback_manager();
|
|
const CallbackManager& callback_manager() const;
|
|
ClassManager& class_manager();
|
|
const ClassManager& class_manager() const;
|
|
|
|
private:
|
|
struct LocalData;
|
|
|
|
VM (Configuration* conf, const detail::Callbacks&, void* user_data, std::uint32_t user_data_type);
|
|
DynafuncMaker* dynafunc_maker();
|
|
std::uint32_t user_data_type() const;
|
|
void* void_user_data();
|
|
void set_user_data (void* user_data, std::uint32_t user_data_type);
|
|
template <typename T> detail::Callbacks to_callbacks (T& conf);
|
|
|
|
std::unique_ptr<LocalData> m_local;
|
|
};
|
|
|
|
namespace detail {
|
|
define_method_info(write_fn, write, void, VM*, wren_string_t);
|
|
define_method_info(error_fn, error, void, VM*, ErrorType, wren_string_t, int, wren_string_t);
|
|
define_method_info(reallocate_fn, reallocate, void*, void*, std::size_t);
|
|
define_method_info(resolve_module_fn, resolve_module, wren_string_t, wren_string_t, wren_string_t);
|
|
define_method_info(load_module_fn, load_module, char*, VM*, wren_string_t);
|
|
define_method_info(foreign_method_fn, foreign_method, foreign_method_t, VM*, wren_string_t, wren_string_t, bool, wren_string_t);
|
|
define_method_info(foreign_class_fn, foreign_class, foreign_class_t, VM*, wren_string_t, wren_string_t);
|
|
define_method_info(load_module_complete_fn, load_module_complete, void, VM*, wren_string_t, char*);
|
|
|
|
template <typename T, typename F> struct AnyFunctionWrap;
|
|
template <typename T, typename R, typename... Args>
|
|
struct AnyFunctionWrap<T, R(T::*)(Args...)> {
|
|
template <R(T::*M)(Args...)>
|
|
inline static R call(Configuration& obj, Args... args) {
|
|
return (reinterpret_cast<T&>(obj).*M)(args...);
|
|
}
|
|
};
|
|
template <typename T, typename R, typename... Args>
|
|
struct AnyFunctionWrap<T, R(*)(Args...)> {
|
|
template <R(*M)(Args...)>
|
|
inline static R call(Configuration&, Args... args) {
|
|
return (*M)(args...);
|
|
}
|
|
};
|
|
|
|
template <typename U>
|
|
[[gnu::const]]
|
|
inline constexpr std::uint32_t type_id() {
|
|
return duckcore::StringCRC32(__PRETTY_FUNCTION__);
|
|
}
|
|
} //namespace detail
|
|
|
|
template <typename T>
|
|
inline detail::Callbacks VM::to_callbacks (T& conf) {
|
|
using detail::method_reallocate;
|
|
|
|
detail::Callbacks ret;
|
|
ret.config_obj = &conf;
|
|
ret.owner = this;
|
|
ret.dynafunc = nullptr;
|
|
|
|
if constexpr (detail::method_write::exists<T>::value)
|
|
ret.write_fn = &detail::AnyFunctionWrap<T, decltype(&T::write_fn)>::template call<&T::write_fn>;
|
|
|
|
if constexpr (detail::method_error::exists<T>::value)
|
|
ret.error_fn = &detail::AnyFunctionWrap<T, decltype(&T::error_fn)>::template call<&T::error_fn>;
|
|
|
|
if constexpr (method_reallocate::exists<T>::value and method_reallocate::is_static<T>::value)
|
|
ret.reallocate_fn = &T::reallocate_fn;
|
|
static_assert(not method_reallocate::exists<T>::value or method_reallocate::is_static<T>::value, "Realloc function must be a static function");
|
|
|
|
if constexpr (detail::method_resolve_module::exists<T>::value)
|
|
ret.resolve_module_fn = &detail::AnyFunctionWrap<T, decltype(&T::resolve_module_fn)>::template call<&T::resolve_module_fn>;
|
|
|
|
if constexpr (detail::method_load_module::exists<T>::value)
|
|
ret.load_module_fn = &detail::AnyFunctionWrap<T, decltype(&T::load_module_fn)>::template call<&T::load_module_fn>;
|
|
|
|
if constexpr (detail::method_foreign_method::exists<T>::value)
|
|
ret.foreign_method_fn = &detail::AnyFunctionWrap<T, decltype(&T::foreign_method_fn)>::template call<&T::foreign_method_fn>;
|
|
|
|
if constexpr (detail::method_foreign_class::exists<T>::value)
|
|
ret.foreign_class_fn = &detail::AnyFunctionWrap<T, decltype(&T::foreign_class_fn)>::template call<&T::foreign_class_fn>;
|
|
|
|
if constexpr (detail::method_load_module_complete::exists<T>::value)
|
|
ret.load_module_complete_fn = &detail::AnyFunctionWrap<T, decltype(&T::load_module_complete_fn)>::template call<&T::load_module_complete_fn>;
|
|
|
|
return ret;
|
|
}
|
|
|
|
template <typename U>
|
|
inline U* VM::user_data() {
|
|
if (user_data_type() != detail::type_id<U>()) {
|
|
throw std::runtime_error("Wrong user data type requested");
|
|
}
|
|
return reinterpret_cast<U*>(void_user_data());
|
|
}
|
|
|
|
template <typename U>
|
|
inline void VM::set_user_data (U* user_data) {
|
|
set_user_data(reinterpret_cast<void*>(user_data), detail::type_id<U>());
|
|
}
|
|
|
|
template <typename T>
|
|
inline VM::VM (T* conf, std::nullptr_t) :
|
|
VM(
|
|
static_cast<Configuration*>(conf),
|
|
to_callbacks(*conf),
|
|
nullptr,
|
|
detail::type_id<std::nullptr_t>()
|
|
)
|
|
{
|
|
}
|
|
|
|
template <typename T, typename U>
|
|
inline VM::VM (T* conf, U* user_data) :
|
|
VM(
|
|
static_cast<Configuration*>(conf),
|
|
to_callbacks(*conf),
|
|
reinterpret_cast<void*>(user_data),
|
|
detail::type_id<U>()
|
|
)
|
|
{
|
|
}
|
|
} //namespace wren
|