mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 11:30:18 +00:00
...
This commit is contained in:
parent
7b29b4afb3
commit
349048d456
@ -14,20 +14,26 @@ Special thanks for [@koltenpearson](https://github.com/koltenpearson) for bringi
|
||||
|
||||
## Basic Functions
|
||||
|
||||
#### `pkpy_vm* pkpy_vm_create(bool use_stdio, bool enable_os)`
|
||||
#### `pkpy_vm* pkpy_new_vm(bool enable_os)`
|
||||
|
||||
Creates a new Lua Style VM.
|
||||
Create a new VM.
|
||||
|
||||
+ `use_stdio`: if true, the VM will use stdout and stderr
|
||||
+ `enable_os`: if true, the VM will have access to the os library
|
||||
|
||||
#### `bool pkpy_vm_run(pkpy_vm*, const char* source)`
|
||||
#### `bool pkpy_vm_run(pkpy_vm* vm_handle, const char* source)`
|
||||
|
||||
Runs the given source code in the VM.
|
||||
Run the given source code in the VM.
|
||||
|
||||
+ `source`: the source code to run
|
||||
|
||||
#### `void pkpy_vm_destroy(pkpy_vm*)`
|
||||
#### `void pkpy_delete_vm(pkpy_vm* vm_handle)`
|
||||
|
||||
Destroys the VM.
|
||||
Dispose the VM.
|
||||
|
||||
#### `bool pkpy_vm_exec(pkpy_vm* vm_handle, const char* source)`
|
||||
|
||||
A wrapper of `vm->exec(...)`.
|
||||
|
||||
#### `bool pkpy_vm_exec_2(pkpy_vm* vm_handle, const char* source, const char* filename, int mode, const char* module)`
|
||||
|
||||
A wrapper of `vm->exec_2(...)`.
|
@ -128,6 +128,29 @@ struct FuncDecl {
|
||||
void _gc_mark() const;
|
||||
};
|
||||
|
||||
struct UserData{
|
||||
char data[16];
|
||||
bool empty;
|
||||
|
||||
UserData(): empty(true) {}
|
||||
template<typename T>
|
||||
UserData(T t): empty(false){
|
||||
static_assert(std::is_trivially_copyable_v<T>);
|
||||
static_assert(sizeof(T) <= sizeof(data));
|
||||
memcpy(data, &t, sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T get() const{
|
||||
static_assert(std::is_trivially_copyable_v<T>);
|
||||
static_assert(sizeof(T) <= sizeof(data));
|
||||
#if PK_DEBUG_EXTRA_CHECK
|
||||
PK_ASSERT(!empty);
|
||||
#endif
|
||||
return reinterpret_cast<const T&>(data);
|
||||
}
|
||||
};
|
||||
|
||||
struct NativeFunc {
|
||||
NativeFuncC f;
|
||||
|
||||
@ -137,29 +160,16 @@ struct NativeFunc {
|
||||
// new style decl-based call
|
||||
FuncDecl_ decl;
|
||||
|
||||
using UserData = char[32];
|
||||
UserData _userdata;
|
||||
bool _has_userdata;
|
||||
|
||||
template <typename T>
|
||||
void set_userdata(T data) {
|
||||
static_assert(std::is_trivially_copyable_v<T>);
|
||||
static_assert(sizeof(T) <= sizeof(UserData));
|
||||
if(_has_userdata) throw std::runtime_error("userdata already set");
|
||||
_has_userdata = true;
|
||||
memcpy(_userdata, &data, sizeof(T));
|
||||
void set_userdata(UserData data) {
|
||||
if(!_userdata.empty && !data.empty){
|
||||
// override is not supported
|
||||
throw std::runtime_error("userdata already set");
|
||||
}
|
||||
_userdata = data;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T get_userdata() const {
|
||||
static_assert(std::is_trivially_copyable_v<T>);
|
||||
static_assert(sizeof(T) <= sizeof(UserData));
|
||||
#if PK_DEBUG_EXTRA_CHECK
|
||||
if(!_has_userdata) throw std::runtime_error("userdata not set");
|
||||
#endif
|
||||
return reinterpret_cast<const T&>(_userdata);
|
||||
}
|
||||
|
||||
NativeFunc(NativeFuncC f, int argc, bool method);
|
||||
NativeFunc(NativeFuncC f, FuncDecl_ decl);
|
||||
|
||||
@ -201,8 +211,8 @@ struct Py_<NativeFunc> final: PyObject {
|
||||
|
||||
template<typename T>
|
||||
T lambda_get_userdata(PyObject** p){
|
||||
if(p[-1] != PY_NULL) return PK_OBJ_GET(NativeFunc, p[-1]).get_userdata<T>();
|
||||
else return PK_OBJ_GET(NativeFunc, p[-2]).get_userdata<T>();
|
||||
if(p[-1] != PY_NULL) return PK_OBJ_GET(NativeFunc, p[-1])._userdata.get<T>();
|
||||
else return PK_OBJ_GET(NativeFunc, p[-2])._userdata.get<T>();
|
||||
}
|
||||
|
||||
} // namespace pkpy
|
@ -62,6 +62,9 @@ struct ValueStackImpl {
|
||||
}
|
||||
void clear() { _sp = _begin; }
|
||||
bool is_overflow() const { return _sp >= _max_end; }
|
||||
|
||||
PyObject* operator[](int i) const { return _begin[i]; }
|
||||
PyObject*& operator[](int i) { return _begin[i]; }
|
||||
|
||||
ValueStackImpl(const ValueStackImpl&) = delete;
|
||||
ValueStackImpl(ValueStackImpl&&) = delete;
|
||||
|
@ -14,37 +14,15 @@ typedef struct pkpy_vm_handle pkpy_vm;
|
||||
typedef int (*pkpy_function)(pkpy_vm*);
|
||||
|
||||
/* Basic Functions */
|
||||
PK_EXPORT pkpy_vm* pkpy_vm_create(bool use_stdio, bool enable_os);
|
||||
PK_EXPORT void pkpy_vm_destroy(pkpy_vm*);
|
||||
|
||||
//we we take a lot of inspiration from the lua api for these bindings
|
||||
//the key difference being most methods return a bool,
|
||||
//true if it succeeded false if it did not
|
||||
|
||||
//if a method returns false call the pkpy_clear_error method to check the error and clear it
|
||||
//if pkpy_clear_error returns false it means that no error was set, and it takes no action
|
||||
//if pkpy_clear_error returns true it means there was an error and it was cleared,
|
||||
//it will provide a string summary of the error in the message parameter (if it is not NULL)
|
||||
//if null is passed in as message, and it will just print the message to stderr
|
||||
PK_EXPORT bool pkpy_clear_error(pkpy_vm*, char** message);
|
||||
//NOTE you are responsible for freeing message
|
||||
|
||||
//this will cause the vm to enter an error state and report the given message
|
||||
//when queried
|
||||
//note that at the moment this is more like a panic than throwing an error
|
||||
//the user will not be able to catch it with python code
|
||||
PK_EXPORT bool pkpy_error(pkpy_vm*, const char* name, const char* message);
|
||||
|
||||
|
||||
|
||||
|
||||
PK_EXPORT pkpy_vm* pkpy_new_vm(bool enable_os);
|
||||
PK_EXPORT void pkpy_delete_vm(pkpy_vm* vm);
|
||||
PK_EXPORT bool pkpy_vm_exec(pkpy_vm* vm, const char* source);
|
||||
PK_EXPORT bool pkpy_vm_exec_2(pkpy_vm* vm, const char* source, const char* filename, int mode, const char* module);
|
||||
|
||||
/* Stack Manipulation */
|
||||
PK_EXPORT bool pkpy_pop(pkpy_vm*, int n);
|
||||
|
||||
//push the item at index onto the top of the stack (as well as leaving it where
|
||||
//it is on the stack)
|
||||
PK_EXPORT bool pkpy_push(pkpy_vm*, int index);
|
||||
|
||||
PK_EXPORT bool pkpy_dup_top(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_rot_two(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_push_function(pkpy_vm*, pkpy_function, int);
|
||||
PK_EXPORT bool pkpy_push_int(pkpy_vm*, int);
|
||||
PK_EXPORT bool pkpy_push_float(pkpy_vm*, double);
|
||||
@ -53,26 +31,32 @@ PK_EXPORT bool pkpy_push_string(pkpy_vm*, const char*);
|
||||
PK_EXPORT bool pkpy_push_stringn(pkpy_vm*, const char*, int length);
|
||||
PK_EXPORT bool pkpy_push_voidp(pkpy_vm*, void*);
|
||||
PK_EXPORT bool pkpy_push_none(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_push_eval(pkpy_vm*, const char* source);
|
||||
PK_EXPORT bool pkpy_push_module(pkpy_vm*, const char* name);
|
||||
|
||||
/* Error Handling */
|
||||
|
||||
PK_EXPORT bool pkpy_clear_error(pkpy_vm*, char** message);
|
||||
PK_EXPORT bool pkpy_error(pkpy_vm*, const char* name, const char* message);
|
||||
//will return true if the vm is currently in an error state
|
||||
PK_EXPORT bool pkpy_check_error(pkpy_vm*);
|
||||
|
||||
/* Variables */
|
||||
|
||||
PK_EXPORT bool pkpy_set_global(pkpy_vm*, const char* name);
|
||||
PK_EXPORT bool pkpy_get_global(pkpy_vm*, const char* name);
|
||||
//will return true if global exists
|
||||
PK_EXPORT bool pkpy_check_global(pkpy_vm*, const char* name);
|
||||
PK_EXPORT bool pkpy_getattr(pkpy_vm*, const char* name);
|
||||
PK_EXPORT bool pkpy_setattr(pkpy_vm*, const char* name);
|
||||
|
||||
/* Callables */
|
||||
|
||||
//first push callable you want to call
|
||||
//then push the arguments to send
|
||||
//argc is the number of arguments that was pushed (not counting the callable)
|
||||
PK_EXPORT bool pkpy_call(pkpy_vm*, int argc);
|
||||
|
||||
//first push the object the method belongs to (self)
|
||||
//then push the the argments
|
||||
//argc is the number of arguments that was pushed (not counting the callable or self)
|
||||
//name is the name of the method to call on the object
|
||||
PK_EXPORT bool pkpy_call_method(pkpy_vm*, const char* name, int argc);
|
||||
|
||||
/* Types */
|
||||
|
||||
//we will break with the lua api here
|
||||
//lua uses 1 as the index to the first pushed element for all of these functions
|
||||
//but we will start counting at zero to match python
|
||||
//we will allow negative numbers to count backwards from the top
|
||||
PK_EXPORT bool pkpy_to_int(pkpy_vm*, int index, int* ret);
|
||||
PK_EXPORT bool pkpy_to_float(pkpy_vm*, int index, double* ret);
|
||||
PK_EXPORT bool pkpy_to_bool(pkpy_vm*, int index, bool* ret);
|
||||
@ -97,34 +81,6 @@ PK_EXPORT bool pkpy_is_string(pkpy_vm*, int index);
|
||||
PK_EXPORT bool pkpy_is_voidp(pkpy_vm*, int index);
|
||||
PK_EXPORT bool pkpy_is_none(pkpy_vm*, int index);
|
||||
|
||||
//will return true if global exists
|
||||
PK_EXPORT bool pkpy_check_global(pkpy_vm*, const char* name);
|
||||
|
||||
//will return true if the vm is currently in an error state
|
||||
PK_EXPORT bool pkpy_check_error(pkpy_vm*);
|
||||
|
||||
//will return true if at least free empty slots remain on the stack
|
||||
PK_EXPORT bool pkpy_check_stack(pkpy_vm*, int free);
|
||||
|
||||
//returns the number of elements on the stack
|
||||
PK_EXPORT int pkpy_stack_size(pkpy_vm*);
|
||||
|
||||
PK_EXPORT bool pkpy_getattr(pkpy_vm*, const char* name);
|
||||
PK_EXPORT bool pkpy_setattr(pkpy_vm*, const char* name);
|
||||
PK_EXPORT bool pkpy_eval(pkpy_vm*, const char* source);
|
||||
|
||||
// create a new native module with the given name and push it onto the stack
|
||||
PK_EXPORT bool pkpy_new_module(void* vm, const char* name);
|
||||
|
||||
|
||||
/* vm api */
|
||||
|
||||
// for backwards compatibility
|
||||
#define pkpy_vm_run(vm, source) pkpy_vm_exec(vm, source)
|
||||
|
||||
PK_EXPORT bool pkpy_vm_exec(pkpy_vm* vm, const char* source);
|
||||
PK_EXPORT bool pkpy_vm_exec_2(pkpy_vm* vm, const char* source, const char* filename, int mode, const char* module);
|
||||
|
||||
/* special api */
|
||||
|
||||
// free a pointer allocated from pkpy's heap
|
||||
|
@ -117,9 +117,6 @@ public:
|
||||
NameDict _modules; // loaded modules
|
||||
std::map<StrName, Str> _lazy_modules; // lazy loaded modules
|
||||
|
||||
PyObject* _reg[32]; // registers for user purpose, also used by C-API
|
||||
static constexpr int REG_COUNT = sizeof(_reg) / sizeof(void*);
|
||||
|
||||
PyObject* None;
|
||||
PyObject* True;
|
||||
PyObject* False;
|
||||
@ -456,8 +453,8 @@ public:
|
||||
PyObject* _py_generator(Frame&& frame, ArgsView buffer);
|
||||
void _prepare_py_call(PyObject**, ArgsView, ArgsView, const FuncDecl_&);
|
||||
// new style binding api
|
||||
PyObject* bind(PyObject*, const char*, const char*, NativeFuncC, void* userdata=nullptr);
|
||||
PyObject* bind(PyObject*, const char*, NativeFuncC, void* userdata=nullptr);
|
||||
PyObject* bind(PyObject*, const char*, const char*, NativeFuncC, UserData userdata={});
|
||||
PyObject* bind(PyObject*, const char*, NativeFuncC, UserData userdata={});
|
||||
};
|
||||
|
||||
DEF_NATIVE_2(Str, tp_str)
|
||||
|
@ -1,77 +1,60 @@
|
||||
#include "pocketpy.h"
|
||||
#include "pocketpy/tuplelist.h"
|
||||
#include "pocketpy_c.h"
|
||||
|
||||
using namespace pkpy;
|
||||
|
||||
typedef int (*LuaStyleFuncC)(VM*);
|
||||
|
||||
struct LuaStack: public ValueStackImpl<32>{
|
||||
PyObject*& at(int i) {
|
||||
if(i < 0 || i >= size()){
|
||||
throw std::runtime_error("lua stack index out of range");
|
||||
}
|
||||
return _begin[i];
|
||||
}
|
||||
PyObject* const& at(int i) const {
|
||||
if(i < 0 || i >= size()){
|
||||
throw std::runtime_error("lua stack index out of range");
|
||||
}
|
||||
return _begin[i];
|
||||
}
|
||||
|
||||
void safe_push(PyObject* obj){
|
||||
if(size() >= max_size()) throw std::runtime_error("lua stack overflow");
|
||||
push(obj);
|
||||
}
|
||||
|
||||
void safe_pop(){
|
||||
if(size() == 0) throw std::runtime_error("lua stack is empty");
|
||||
pop();
|
||||
}
|
||||
|
||||
PyObject*& safe_top(){
|
||||
if(size() == 0) throw std::runtime_error("lua stack is empty");
|
||||
return top();
|
||||
}
|
||||
};
|
||||
|
||||
#define ERRHANDLER_OPEN \
|
||||
if (vm->error != nullptr) \
|
||||
if (vm->_c.error != nullptr) \
|
||||
return false; \
|
||||
try {
|
||||
|
||||
#define ERRHANDLER_CLOSE \
|
||||
} catch(Exception& e ) { \
|
||||
vm->error = py_var(vm, e); \
|
||||
vm->_c.error = py_var(vm, e); \
|
||||
return false; \
|
||||
} catch(const std::exception& re){ \
|
||||
auto e = Exception("std::exception", re.what()); \
|
||||
vm->error = py_var(vm, e); \
|
||||
vm->_c.error = py_var(vm, e); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
pkpy_vm* pkpy_new_vm(bool enable_os){
|
||||
return (pkpy_vm*)new VM(enable_os);
|
||||
}
|
||||
|
||||
class CVM: public VM {
|
||||
public:
|
||||
LuaStack c_data; // operation stack
|
||||
PyObject* error;
|
||||
void pkpy_delete_vm(pkpy_vm* vm){
|
||||
return delete (VM*)vm;
|
||||
}
|
||||
|
||||
CVM(bool use_stdio, bool enable_os) : VM(enable_os) {
|
||||
error = nullptr;
|
||||
heap._gc_marker_ex = [](VM* vm_) {
|
||||
CVM* vm = (CVM*)vm_;
|
||||
for(PyObject* obj: vm->c_data) if(obj!=nullptr) PK_OBJ_MARK(obj);
|
||||
if(vm->error != nullptr) PK_OBJ_MARK(vm->error);
|
||||
};
|
||||
bool pkpy_vm_exec(pkpy_vm* vm_handle, const char* source) {
|
||||
VM* vm = (VM*) vm_handle;
|
||||
PyObject* res;
|
||||
ERRHANDLER_OPEN
|
||||
CodeObject_ code = vm->compile(source, "main.py", EXEC_MODE);
|
||||
res = vm->_exec(code, vm->_main);
|
||||
ERRHANDLER_CLOSE
|
||||
return res != nullptr;
|
||||
}
|
||||
|
||||
if (!use_stdio) {
|
||||
_stdout = _stderr = [](VM* vm, const Str& s){
|
||||
PK_UNUSED(vm);
|
||||
PK_UNUSED(s);
|
||||
};
|
||||
}
|
||||
bool pkpy_vm_exec_2(pkpy_vm* vm_handle, const char* source, const char* filename, int mode, const char* module){
|
||||
VM* vm = (VM*) vm_handle;
|
||||
PyObject* res;
|
||||
PyObject* mod;
|
||||
ERRHANDLER_OPEN
|
||||
if(module == nullptr){
|
||||
mod = vm->_main;
|
||||
}else{
|
||||
mod = vm->_modules[module]; // may raise
|
||||
}
|
||||
};
|
||||
CodeObject_ code = vm->compile(source, filename, (CompileMode)mode);
|
||||
res = vm->_exec(code, mod);
|
||||
ERRHANDLER_CLOSE
|
||||
return res != nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//for now I will unpack a tuple automatically, we may not want to handle
|
||||
@ -114,89 +97,34 @@ bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) {
|
||||
return true;
|
||||
}
|
||||
|
||||
pkpy_vm* pkpy_vm_create(bool use_stdio, bool enable_os) {
|
||||
CVM* vm = new CVM(use_stdio, enable_os);
|
||||
return (pkpy_vm*) vm;
|
||||
}
|
||||
|
||||
bool pkpy_vm_exec(pkpy_vm* vm_handle, const char* source) {
|
||||
CVM* vm = (CVM*) vm_handle;
|
||||
PyObject* res;
|
||||
ERRHANDLER_OPEN
|
||||
CodeObject_ code = vm->compile(source, "main.py", EXEC_MODE);
|
||||
res = vm->_exec(code, vm->_main);
|
||||
ERRHANDLER_CLOSE
|
||||
return res != nullptr;
|
||||
}
|
||||
|
||||
bool pkpy_vm_exec_2(pkpy_vm* vm_handle, const char* source, const char* filename, int mode, const char* module){
|
||||
CVM* vm = (CVM*) vm_handle;
|
||||
PyObject* res;
|
||||
PyObject* mod;
|
||||
ERRHANDLER_OPEN
|
||||
if(module == nullptr){
|
||||
mod = vm->_main;
|
||||
}else{
|
||||
mod = vm->_modules[module]; // may raise
|
||||
}
|
||||
CodeObject_ code = vm->compile(source, filename, (CompileMode)mode);
|
||||
res = vm->_exec(code, mod);
|
||||
ERRHANDLER_CLOSE
|
||||
return res != nullptr;
|
||||
}
|
||||
|
||||
void pkpy_vm_destroy(pkpy_vm* vm_handle) {
|
||||
CVM* vm = (CVM*) vm_handle;
|
||||
delete vm;
|
||||
}
|
||||
|
||||
PyObject* c_function_wrapper(VM* vm, ArgsView args) {
|
||||
LuaStyleFuncC f = lambda_get_userdata<LuaStyleFuncC>(args.begin());
|
||||
CVM* cvm = (CVM*) vm;
|
||||
|
||||
//setup c stack
|
||||
LuaStack local_stack;
|
||||
|
||||
for (int i = 0; i < args.size(); i++)
|
||||
local_stack.safe_push(args[i]);
|
||||
|
||||
// tmp is controlled by RAII
|
||||
auto tmp = CVM::TempStack(cvm, &local_stack);
|
||||
int retc = f(cvm);
|
||||
|
||||
PyObject** curr_sp = &vm->s_data.top();
|
||||
int retc = f(vm);
|
||||
// propagate_if_errored
|
||||
if (cvm->error != nullptr){
|
||||
Exception e = _py_cast<Exception&>(vm, cvm->error);
|
||||
cvm->error = nullptr;
|
||||
tmp.restore();
|
||||
if (vm->_c.error != nullptr){
|
||||
Exception e = _py_cast<Exception&>(vm, vm->_c.error);
|
||||
vm->_c.error = nullptr;
|
||||
vm->_error(e);
|
||||
}
|
||||
tmp.restore();
|
||||
|
||||
PyObject* ret = cvm->None;
|
||||
|
||||
if (retc == 1)
|
||||
ret = local_stack.safe_top();
|
||||
else if (retc > 1) {
|
||||
Tuple t(retc);
|
||||
|
||||
for (int i = 0; i < retc; i++) {
|
||||
int stack_index = (local_stack.size() - retc) + i;
|
||||
t[i] = local_stack.at(stack_index);
|
||||
}
|
||||
|
||||
ret = py_var(cvm, t);
|
||||
}
|
||||
|
||||
return ret;
|
||||
PK_ASSERT(retc == vm->s_data._sp-curr_sp);
|
||||
if(retc == 0) return vm->None;
|
||||
if (retc == 1) return vm->s_data.popx();
|
||||
ArgsView ret_view(curr_sp, vm->s_data._sp);
|
||||
return py_var(vm, ret_view.to_tuple());
|
||||
}
|
||||
|
||||
bool pkpy_push_function(pkpy_vm* vm_handle, pkpy_function f, int argc) {
|
||||
CVM* vm = (CVM*) vm_handle;
|
||||
NativeFunc nf = NativeFunc(c_function_wrapper, argc, false);
|
||||
nf.set_userdata(f);
|
||||
bool pkpy_push_function(pkpy_vm* vm_handle, const char* sig, pkpy_function f) {
|
||||
VM* vm = (VM*) vm_handle;
|
||||
ERRHANDLER_OPEN
|
||||
vm->c_data->safe_push(py_var(vm, nf));
|
||||
PyObject* f_obj = vm->bind(
|
||||
nullptr,
|
||||
sig,
|
||||
nullptr,
|
||||
c_function_wrapper,
|
||||
f
|
||||
);
|
||||
vm->s_data.push(f_obj);
|
||||
ERRHANDLER_CLOSE
|
||||
return true;
|
||||
}
|
||||
|
14
src/vm.cpp
14
src/vm.cpp
@ -4,7 +4,6 @@ namespace pkpy{
|
||||
|
||||
VM::VM(bool enable_os) : heap(this), enable_os(enable_os) {
|
||||
this->vm = this;
|
||||
for(int i=0; i<REG_COUNT; i++) _reg[i] = nullptr;
|
||||
_stdout = [](VM* vm, const Str& s) {
|
||||
PK_UNUSED(vm);
|
||||
std::cout << s;
|
||||
@ -957,11 +956,11 @@ void VM::setattr(PyObject* obj, StrName name, PyObject* value){
|
||||
obj->attr().set(name, value);
|
||||
}
|
||||
|
||||
PyObject* VM::bind(PyObject* obj, const char* sig, NativeFuncC fn, void* userdata){
|
||||
PyObject* VM::bind(PyObject* obj, const char* sig, NativeFuncC fn, UserData userdata){
|
||||
return bind(obj, sig, nullptr, fn, userdata);
|
||||
}
|
||||
|
||||
PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, NativeFuncC fn, void* userdata){
|
||||
PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, NativeFuncC fn, UserData userdata){
|
||||
CodeObject_ co;
|
||||
try{
|
||||
// fn(a, b, *c, d=1) -> None
|
||||
@ -978,10 +977,8 @@ PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Native
|
||||
decl->docstring = Str(docstring).strip();
|
||||
}
|
||||
PyObject* f_obj = VAR(NativeFunc(fn, decl));
|
||||
if(userdata != nullptr){
|
||||
PK_OBJ_GET(NativeFunc, f_obj).set_userdata(userdata);
|
||||
}
|
||||
obj->attr().set(decl->code->name, f_obj);
|
||||
PK_OBJ_GET(NativeFunc, f_obj).set_userdata(userdata);
|
||||
if(obj != nullptr) obj->attr().set(decl->code->name, f_obj);
|
||||
return f_obj;
|
||||
}
|
||||
|
||||
@ -1000,9 +997,6 @@ void ManagedHeap::mark() {
|
||||
for(PyObject* obj: vm->s_data) PK_OBJ_MARK(obj);
|
||||
if(_gc_marker_ex) _gc_marker_ex(vm);
|
||||
if(vm->_last_exception) PK_OBJ_MARK(vm->_last_exception);
|
||||
for(int i=0; i<vm->REG_COUNT; i++){
|
||||
if(vm->_reg[i] != nullptr) PK_OBJ_MARK(vm->_reg[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Str obj_type_name(VM *vm, Type type){
|
||||
|
Loading…
x
Reference in New Issue
Block a user