diff --git a/src/pywrenppmodule.cpp b/src/pywrenppmodule.cpp index 269dd4d..caa8706 100644 --- a/src/pywrenppmodule.cpp +++ b/src/pywrenppmodule.cpp @@ -1,14 +1,22 @@ #define PY_SSIZE_T_CLEAN #include #include "wrenpp/vm.hpp" +#include "wrenpp/vm_fun.hpp" #include "wrenpp/def_configuration.hpp" #include "config.h" +#include +#include +#include -#define CURR_MODULE_NAME WRENPP_NAME +#define CURR_MODULE_NAME "py" WRENPP_NAME namespace { struct VMObject; int vm_init (VMObject* self, PyObject*, PyObject*); +PyObject* vm_new (PyTypeObject* type, PyObject*, PyObject*); +void vm_dealloc (VMObject* self); +PyObject* vm_interpret (VMObject* self, PyObject* args); +PyObject* vm_call (VMObject* self, PyObject* args); class VMConfig : public wren::DefConfiguration { public: @@ -40,31 +48,117 @@ struct VMObject { PyObject_HEAD wren::VM vm; }; +//PyMemberDef VMProperties[] = { +// {nullptr} +//}; +PyMethodDef VMMethods[] = { + { + "interpret", + reinterpret_cast(vm_interpret), + METH_VARARGS, + "Interpret a string script" + }, + { + "call", + reinterpret_cast(vm_call), + METH_VARARGS, + "Call a method from a previously parsed script" + }, + {nullptr} +}; PyTypeObject VMType = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = CURR_MODULE_NAME ".VM", .tp_basicsize = sizeof(VMObject), .tp_itemsize = 0, + .tp_dealloc = reinterpret_cast(vm_dealloc), .tp_flags = Py_TPFLAGS_DEFAULT, .tp_doc = "Wrenpp VM", + .tp_methods = VMMethods, + .tp_members = nullptr, //VMProperties, .tp_init = reinterpret_cast(vm_init), - .tp_new = PyType_GenericNew, + .tp_new = vm_new, }; +PyObject* vm_new (PyTypeObject* type, PyObject* /*args*/, PyObject* /*kwds*/) { + VMObject* const self = reinterpret_cast(type->tp_alloc(type, 0)); + if (self) { + try { + VMConfig config; + new(&self->vm) wren::VM(&config, nullptr); + } + catch (...) { + Py_DECREF(self); + return nullptr; + } + } + return reinterpret_cast(self); +} + +void vm_dealloc (VMObject* self) { + self->vm.~VM(); +} + int vm_init (VMObject* self, PyObject* /*args*/, PyObject* /*kwds*/) { - try { - VMConfig config; - new(&self->vm) wren::VM(&config, nullptr); - } - catch (...) { - return -1; - } + VMConfig config; + self->vm.reset(&config); return 0; } + +PyObject* vm_interpret (VMObject* self, PyObject* args) { + const char* module_name; + const char* script; + if (!PyArg_ParseTuple(args, "ss", &module_name, &script)) + return NULL; + + self->vm.interpret(module_name, script); + Py_RETURN_NONE; +} + +PyObject* vm_call (VMObject* self, PyObject* args) { + const Py_ssize_t argc = PyTuple_Size(args); + std::vector objects; + objects.reserve(argc); + + self->vm.ensure_slots(static_cast(argc) + 1); + variable(self->vm, wren::ModuleAndName{"main", "the_user"}, 0); + + std::string func_sig; + { + Py_ssize_t sz; + PyObject* const obj = PyTuple_GetItem(args, 0); + const char* const buf = PyUnicode_AsUTF8AndSize(obj, &sz); + func_sig.reserve(sz + 3); + func_sig.append(buf, sz); + func_sig.append(1, '('); + } + + for (Py_ssize_t z = 1; z < argc; ++z) { + PyObject* const obj = PyTuple_GetItem(args, z); + if (not obj) + return nullptr; + + const std::string_view type_name(Py_TYPE(obj)->tp_name); + //std::cout << "vm_call, parameter " << z+1 << " has type \"" << type_name << "\"\n"; + if (type_name == "str") { + const char* const buf = PyUnicode_AsUTF8(obj); + self->vm.set_slot_string(static_cast(z), buf); + } + func_sig += "_,"; + } + + if (func_sig.back() == ',') + func_sig.resize(func_sig.size() - 1); + func_sig += ")"; + auto handle = self->vm.make_call_handle(func_sig.c_str()); + self->vm.call(handle); + + Py_RETURN_NONE; +} } //unnamed namespace -PyMODINIT_FUNC PyInit_wrenpp(void) { +PyMODINIT_FUNC PyInit_pywrenpp(void) { if (PyType_Ready(&VMType) < 0) return nullptr; PyObject* const m = PyModule_Create(&WrenppModule);