Allow foreign_method_fn() in the configuration object.
Wren expects this function to return a pointer to a function that takes a WrenVM*. This is bad news because that type is wrapped inside wren::VM and client code doesn't know about it. It would be better for client code to return a pointer to a function that takes a VM* instead. In order to do the VM* to WrenVM* translation I make a "handmade" closure, that is I generate a function at runtime that contains the VM* hardcoded into it. The same function also contains the hardcoded address of the callback function client code wanted to use. By doing this I can pass a different function pointer to Wren for each foreign method, and that function knows how to forward the call to the real client callback. Currently only implemented for amd64 gnu/linux.
This commit is contained in:
parent
d0be115181
commit
16c4b8cbe5
9 changed files with 187 additions and 4 deletions
|
@ -1,5 +1,6 @@
|
|||
#include "vm.hpp"
|
||||
#include "configuration.hpp"
|
||||
#include "dynafunc_maker.hpp"
|
||||
#include <wren.hpp>
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
|
@ -43,13 +44,26 @@ namespace wren {
|
|||
assert(cb->load_module_fn and cb->config_obj and cb->owner);
|
||||
return cb->load_module_fn(*cb->config_obj, cb->owner, name);
|
||||
}
|
||||
|
||||
WrenForeignMethodFn foreign_method_fn (WrenVM* wvm, const char* module, const char* class_name, bool is_static, const char* signature) {
|
||||
auto cb = static_cast<detail::Callbacks*>(wrenGetUserData(wvm));
|
||||
assert(cb);
|
||||
assert(cb->foreign_method_fn and cb->config_obj and cb->owner);
|
||||
foreign_method_t func = cb->foreign_method_fn(*cb->config_obj, cb->owner, module, class_name, is_static, signature);
|
||||
DynafuncMaker* const dfm = cb->dynafunc;
|
||||
assert(dfm);
|
||||
auto retval = reinterpret_cast<WrenForeignMethodFn>(dfm->make(cb->owner, func));
|
||||
return retval;
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
struct VM::LocalData {
|
||||
explicit LocalData (const detail::Callbacks& cb) :
|
||||
callbacks(cb),
|
||||
wvm(nullptr)
|
||||
{}
|
||||
{
|
||||
callbacks.dynafunc = &dynafunc;
|
||||
}
|
||||
~LocalData() noexcept {
|
||||
if (wvm)
|
||||
wrenFreeVM(wvm);
|
||||
|
@ -59,6 +73,7 @@ namespace wren {
|
|||
}
|
||||
|
||||
detail::Callbacks callbacks;
|
||||
DynafuncMaker dynafunc;
|
||||
WrenVM* wvm;
|
||||
};
|
||||
|
||||
|
@ -88,15 +103,20 @@ namespace wren {
|
|||
if (cb.load_module_fn)
|
||||
wconf.loadModuleFn = &load_module_fn;
|
||||
|
||||
if (cb.foreign_method_fn)
|
||||
wconf.bindForeignMethodFn = &foreign_method_fn;
|
||||
|
||||
m_local->wvm = wrenNewVM(&wconf);
|
||||
if (not m_local->wvm)
|
||||
throw std::runtime_error("Failed to initialize Wren VM");
|
||||
}
|
||||
|
||||
VM::VM (VM&& other) = default;
|
||||
VM::~VM() noexcept = default;
|
||||
|
||||
DynafuncMaker* VM::dynafunc_maker() {
|
||||
return &m_local->dynafunc;
|
||||
}
|
||||
|
||||
void VM::interpret (const char* module_name, const char* script) {
|
||||
using std::string;
|
||||
using std::runtime_error;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue