Move files around
Sample main.cpp is now into examples/greet
This commit is contained in:
parent
a3c1199da9
commit
65189a5575
13 changed files with 30 additions and 13 deletions
312
src/vm.cpp
Normal file
312
src/vm.cpp
Normal file
|
@ -0,0 +1,312 @@
|
|||
/* Copyright 2020, 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/>.
|
||||
*/
|
||||
|
||||
#include "wrenpp/vm.hpp"
|
||||
#include "wrenpp/configuration.hpp"
|
||||
#include "dynafunc_maker.hpp"
|
||||
#include <wren.hpp>
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace wren {
|
||||
namespace {
|
||||
[[gnu::const]]
|
||||
ErrorType to_error_type (WrenErrorType wet) {
|
||||
switch (wet) {
|
||||
case WREN_ERROR_COMPILE: return ErrorType::Compile;
|
||||
case WREN_ERROR_RUNTIME: return ErrorType::Runtime;
|
||||
case WREN_ERROR_STACK_TRACE: return ErrorType::StackTrace;
|
||||
default: return ErrorType::Runtime;
|
||||
};
|
||||
}
|
||||
|
||||
void write_fn (WrenVM* wvm, const char* text) {
|
||||
auto cb = static_cast<detail::Callbacks*>(wrenGetUserData(wvm));
|
||||
assert(cb);
|
||||
assert(cb->write_fn and cb->config_obj and cb->owner);
|
||||
cb->write_fn(*cb->config_obj, cb->owner, text);
|
||||
}
|
||||
|
||||
void error_fn (WrenVM* wvm, WrenErrorType type, const char* module, int line, const char* message) {
|
||||
auto cb = static_cast<detail::Callbacks*>(wrenGetUserData(wvm));
|
||||
assert(cb);
|
||||
assert(cb->error_fn and cb->config_obj and cb->owner);
|
||||
cb->error_fn(*cb->config_obj, cb->owner, to_error_type(type), module, line, message);
|
||||
}
|
||||
|
||||
const char* resolve_module_fn (WrenVM* wvm, const char* importer, const char* name) {
|
||||
auto cb = static_cast<detail::Callbacks*>(wrenGetUserData(wvm));
|
||||
assert(cb);
|
||||
assert(cb->resolve_module_fn and cb->config_obj and cb->owner);
|
||||
return cb->resolve_module_fn(*cb->config_obj, cb->owner, importer, name);
|
||||
}
|
||||
|
||||
char* load_module_fn (WrenVM* wvm, const char* name) {
|
||||
auto cb = static_cast<detail::Callbacks*>(wrenGetUserData(wvm));
|
||||
assert(cb);
|
||||
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);
|
||||
if (func) {
|
||||
DynafuncMaker* const dfm = cb->dynafunc;
|
||||
assert(dfm);
|
||||
auto retval = reinterpret_cast<WrenForeignMethodFn>(dfm->make(cb->owner, func));
|
||||
return retval;
|
||||
}
|
||||
else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
WrenForeignClassMethods foreign_class_fn (WrenVM* wvm, const char* module, const char* class_name) {
|
||||
auto cb = static_cast<detail::Callbacks*>(wrenGetUserData(wvm));
|
||||
assert(cb);
|
||||
assert(cb->foreign_class_fn and cb->config_obj and cb->owner);
|
||||
foreign_class_t funcs = cb->foreign_class_fn(*cb->config_obj, cb->owner, module, class_name);
|
||||
WrenForeignClassMethods retval;
|
||||
if (funcs.allocate) {
|
||||
DynafuncMaker* const dfm = cb->dynafunc;
|
||||
assert(dfm);
|
||||
retval.allocate = reinterpret_cast<WrenForeignMethodFn>(dfm->make(cb->owner, funcs.allocate));
|
||||
}
|
||||
else {
|
||||
retval.allocate = nullptr;
|
||||
}
|
||||
retval.finalize = funcs.finalize;
|
||||
return retval;
|
||||
}
|
||||
|
||||
void throw_if_err (WrenInterpretResult res, const char* module_name) {
|
||||
using std::runtime_error;
|
||||
using std::string;
|
||||
|
||||
switch (res) {
|
||||
case WREN_RESULT_COMPILE_ERROR:
|
||||
throw runtime_error(string("Compilation of ") + module_name + " has failed");
|
||||
case WREN_RESULT_RUNTIME_ERROR:
|
||||
throw runtime_error(string("A runtime error occurred in ") + module_name);
|
||||
|
||||
case WREN_RESULT_SUCCESS:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
struct VM::LocalData {
|
||||
explicit LocalData (const detail::Callbacks& cb) :
|
||||
callbacks(cb),
|
||||
wvm(nullptr)
|
||||
{
|
||||
callbacks.dynafunc = &dynafunc;
|
||||
}
|
||||
~LocalData() noexcept {
|
||||
if (wvm)
|
||||
wrenFreeVM(wvm);
|
||||
#if !defined(NDEBUG)
|
||||
wvm = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
detail::Callbacks callbacks;
|
||||
DynafuncMaker dynafunc;
|
||||
WrenVM* wvm;
|
||||
void* user_data;
|
||||
std::uint32_t user_data_type;
|
||||
};
|
||||
|
||||
VM::VM (Configuration* conf, const detail::Callbacks& cb, void* user_data, std::uint32_t user_data_type) :
|
||||
m_local(std::make_unique<LocalData>(cb))
|
||||
{
|
||||
WrenConfiguration wconf;
|
||||
wrenInitConfiguration(&wconf);
|
||||
wconf.userData = static_cast<void*>(&m_local->callbacks);
|
||||
|
||||
wconf.initialHeapSize = conf->initial_heap_size();
|
||||
wconf.minHeapSize = conf->min_heap_size();
|
||||
wconf.heapGrowthPercent = conf->heap_growth_percent();
|
||||
|
||||
if (cb.write_fn)
|
||||
wconf.writeFn = &write_fn;
|
||||
|
||||
if (cb.error_fn)
|
||||
wconf.errorFn = &error_fn;
|
||||
|
||||
if (cb.reallocate_fn)
|
||||
wconf.reallocateFn = cb.reallocate_fn;
|
||||
|
||||
if (cb.resolve_module_fn)
|
||||
wconf.resolveModuleFn = &resolve_module_fn;
|
||||
|
||||
if (cb.load_module_fn)
|
||||
wconf.loadModuleFn = &load_module_fn;
|
||||
|
||||
if (cb.foreign_method_fn)
|
||||
wconf.bindForeignMethodFn = &foreign_method_fn;
|
||||
|
||||
if (cb.foreign_class_fn)
|
||||
wconf.bindForeignClassFn = &foreign_class_fn;
|
||||
|
||||
m_local->wvm = wrenNewVM(&wconf);
|
||||
if (not m_local->wvm)
|
||||
throw std::runtime_error("Failed to initialize Wren VM");
|
||||
|
||||
m_local->user_data = user_data;
|
||||
m_local->user_data_type = user_data_type;
|
||||
}
|
||||
|
||||
VM::~VM() noexcept = default;
|
||||
|
||||
DynafuncMaker* VM::dynafunc_maker() {
|
||||
return &m_local->dynafunc;
|
||||
}
|
||||
|
||||
std::uint32_t VM::user_data_type() const {
|
||||
return m_local->user_data_type;
|
||||
}
|
||||
|
||||
void* VM::void_user_data() {
|
||||
return m_local->user_data;
|
||||
}
|
||||
|
||||
void VM::set_user_data (void* user_data, std::uint32_t user_data_type) {
|
||||
m_local->user_data = user_data;
|
||||
m_local->user_data_type = user_data_type;
|
||||
}
|
||||
|
||||
void VM::interpret (const char* module_name, const char* script) {
|
||||
using std::string;
|
||||
using std::runtime_error;
|
||||
|
||||
const WrenInterpretResult res = wrenInterpret(m_local->wvm, module_name, script);
|
||||
throw_if_err(res, module_name);
|
||||
}
|
||||
|
||||
void VM::call (const Handle& method) {
|
||||
const WrenInterpretResult res = wrenCall(m_local->wvm, method);
|
||||
throw_if_err(res, "[wrenCall()]");
|
||||
}
|
||||
|
||||
void VM::release_handle (Handle& handle) noexcept {
|
||||
if (handle)
|
||||
wrenReleaseHandle(m_local->wvm, handle);
|
||||
}
|
||||
|
||||
void VM::set_slot_string (int slot_num, const char* value) {
|
||||
wrenSetSlotString(m_local->wvm, slot_num, value);
|
||||
}
|
||||
|
||||
void VM::set_slot_double (int slot_num, double value) {
|
||||
wrenSetSlotDouble(m_local->wvm, slot_num, value);
|
||||
}
|
||||
|
||||
void VM::set_slot_bool (int slot_num, bool value) {
|
||||
wrenSetSlotBool(m_local->wvm, slot_num, value);
|
||||
}
|
||||
|
||||
void VM::set_slot_null (int slot_num) {
|
||||
wrenSetSlotNull(m_local->wvm, slot_num);
|
||||
}
|
||||
|
||||
void VM::set_slot_bytes (int slot_num, const char* bytes, std::size_t length) {
|
||||
wrenSetSlotBytes(m_local->wvm, slot_num, bytes, length);
|
||||
}
|
||||
|
||||
void* VM::set_slot_new_foreign (int slot_num, int class_slot, std::size_t size) {
|
||||
return wrenSetSlotNewForeign(m_local->wvm, slot_num, class_slot, size);
|
||||
}
|
||||
|
||||
bool VM::slot_bool (int slot_num) {
|
||||
assert(SlotType::Bool == slot_type(slot_num));
|
||||
return wrenGetSlotBool(m_local->wvm, slot_num);
|
||||
}
|
||||
|
||||
const char* VM::slot_string (int slot_num) {
|
||||
assert(SlotType::String == slot_type(slot_num));
|
||||
return wrenGetSlotString(m_local->wvm, slot_num);
|
||||
}
|
||||
|
||||
double VM::slot_double (int slot_num) {
|
||||
assert(SlotType::Num == slot_type(slot_num));
|
||||
return wrenGetSlotDouble(m_local->wvm, slot_num);
|
||||
}
|
||||
|
||||
std::pair<const char*, int> VM::slot_bytes (int slot_num) {
|
||||
assert(SlotType::String == slot_type(slot_num));
|
||||
int length;
|
||||
const char* const data = wrenGetSlotBytes(m_local->wvm, slot_num, &length);
|
||||
return {data, length};
|
||||
}
|
||||
|
||||
void* VM::slot_foreign (int slot_num) {
|
||||
assert(SlotType::Foreign == slot_type(slot_num));
|
||||
return wrenGetSlotForeign(m_local->wvm, slot_num);
|
||||
}
|
||||
|
||||
void VM::set_user_data (std::nullptr_t) {
|
||||
m_local->user_data = nullptr;
|
||||
m_local->user_data_type = detail::type_id<std::nullptr_t>();
|
||||
}
|
||||
|
||||
bool VM::has_user_data() const {
|
||||
return nullptr != m_local->user_data;
|
||||
}
|
||||
|
||||
void VM::ensure_slots (int num_slots) {
|
||||
wrenEnsureSlots(m_local->wvm, num_slots);
|
||||
}
|
||||
|
||||
int VM::slot_count() {
|
||||
return wrenGetSlotCount(m_local->wvm);
|
||||
}
|
||||
|
||||
void VM::variable(const char* module, const char* name, int slot) {
|
||||
wrenGetVariable(m_local->wvm, module, name, slot);
|
||||
}
|
||||
|
||||
void VM::set_slot_handle (const Handle& handle, int slot) {
|
||||
wrenSetSlotHandle(m_local->wvm, slot, handle);
|
||||
}
|
||||
|
||||
SlotType VM::slot_type(int slot_num) {
|
||||
const WrenType tp = wrenGetSlotType(m_local->wvm, slot_num);
|
||||
switch (tp) {
|
||||
case WREN_TYPE_NUM: return SlotType::Num;
|
||||
case WREN_TYPE_BOOL: return SlotType::Bool;
|
||||
case WREN_TYPE_LIST: return SlotType::List;
|
||||
case WREN_TYPE_NULL: return SlotType::Null;
|
||||
case WREN_TYPE_STRING: return SlotType::String;
|
||||
case WREN_TYPE_FOREIGN: return SlotType::Foreign;
|
||||
case WREN_TYPE_UNKNOWN: return SlotType::Unknown;
|
||||
};
|
||||
assert(false);
|
||||
return SlotType::Unknown;
|
||||
}
|
||||
|
||||
Handle VM::slot_handle(int slot_num) {
|
||||
return {this, wrenGetSlotHandle(m_local->wvm, slot_num)};
|
||||
}
|
||||
|
||||
Handle VM::make_call_handle(const char* signature) {
|
||||
return {this, wrenMakeCallHandle(m_local->wvm, signature)};
|
||||
}
|
||||
} //namespace wren
|
Loading…
Add table
Add a link
Reference in a new issue