This commit is contained in:
blueloveTH 2023-07-08 19:43:17 +08:00
parent 15b92d5fb4
commit 53d272ce2f
7 changed files with 138 additions and 59 deletions

View File

@ -9,7 +9,7 @@ pipeline = [
["config.h", "common.h", "memory.h", "vector.h", "str.h", "tuplelist.h", "namedict.h", "error.h", "lexer.h"],
["obj.h", "dict.h", "codeobject.h", "frame.h"],
["gc.h", "vm.h", "ceval.h", "expr.h", "compiler.h", "repl.h"],
["_generated.h", "cffi.h", "iter.h", "base64.h", "random.h", "re.h", "linalg.h", "easing.h", "io.h"],
["_generated.h", "cffi.h", "bindings.h", "iter.h", "base64.h", "random.h", "re.h", "linalg.h", "easing.h", "io.h"],
["export.h", "pocketpy.h"]
]

125
include/pocketpy/bindings.h Normal file
View File

@ -0,0 +1,125 @@
#pragma once
#include "cffi.h"
namespace pkpy{
struct NativeProxyFuncCBase {
virtual PyObject* operator()(VM* vm, ArgsView args) = 0;
};
template<typename Ret, typename... Params>
struct NativeProxyFuncC final: NativeProxyFuncCBase {
static constexpr int N = sizeof...(Params);
using _Fp = Ret(*)(Params...);
_Fp func;
NativeProxyFuncC(_Fp func) : func(func) {}
PyObject* operator()(VM* vm, ArgsView args) override {
PK_ASSERT(args.size() == N);
return call<Ret>(vm, args, std::make_index_sequence<N>());
}
template<typename __Ret, size_t... Is>
PyObject* call(VM* vm, ArgsView args, std::index_sequence<Is...>){
if constexpr(std::is_void_v<__Ret>){
func(py_cast<Params>(vm, args[Is])...);
return vm->None;
}else{
__Ret ret = func(py_cast<Params>(vm, args[Is])...);
return VAR(std::move(ret));
}
}
};
template<typename Ret, typename T, typename... Params>
struct NativeProxyMethodC final: NativeProxyFuncCBase {
static constexpr int N = sizeof...(Params) + 1;
using _Fp = Ret(T::*)(Params...);
_Fp func;
NativeProxyMethodC(_Fp func) : func(func) {}
PyObject* operator()(VM* vm, ArgsView args) override {
PK_ASSERT(args.size() == N);
return call<Ret>(vm, args, std::make_index_sequence<N>());
}
template<typename __Ret, size_t... Is>
PyObject* call(VM* vm, ArgsView args, std::index_sequence<Is...>){
T& self = py_cast<T&>(vm, args[0]);
if constexpr(std::is_void_v<__Ret>){
(self.*func)(py_cast<Params>(vm, args[Is+1])...);
return vm->None;
}else{
__Ret ret = (self.*func)(py_cast<Params>(vm, args[Is+1])...);
return VAR(std::move(ret));
}
}
};
inline PyObject* proxy_wrapper(VM* vm, ArgsView args){
NativeProxyFuncCBase* pf = lambda_get_userdata<NativeProxyFuncCBase*>(args.begin());
return (*pf)(vm, args);
}
template<typename Ret, typename... Params>
void _bind(VM* vm, PyObject* obj, const char* sig, Ret(*func)(Params...)){
auto proxy = new NativeProxyFuncC<Ret, Params...>(func);
vm->bind(obj, sig, proxy_wrapper, proxy);
}
template<typename Ret, typename T, typename... Params>
void _bind(VM* vm, PyObject* obj, const char* sig, Ret(T::*func)(Params...)){
auto proxy = new NativeProxyMethodC<Ret, T, Params...>(func);
vm->bind(obj, sig, proxy_wrapper, proxy);
}
/*****************************************************************/
template<typename T>
struct OpaquePointer{
T* ptr;
OpaquePointer(T* ptr): ptr(ptr){}
T* operator->(){ return ptr; }
};
#define PK_REGISTER_FIELD(T, NAME) \
type->attr().set(#NAME, vm->property( \
[](VM* vm, ArgsView args){ \
T& self = _CAST(T&, args[0]); \
return VAR(self->NAME); \
}, \
[](VM* vm, ArgsView args){ \
T& self = _CAST(T&, args[0]); \
self->NAME = CAST(decltype(self->NAME), args[1]); \
return vm->None; \
}));
#define PK_REGISTER_READONLY_FIELD(T, NAME) \
type->attr().set(#NAME, vm->property( \
[](VM* vm, ArgsView args){ \
T& self = _CAST(T&, args[0]); \
return VAR(self->NAME); \
}));
#define PK_REGISTER_PROPERTY(T, NAME) \
type->attr().set(#NAME, vm->property( \
[](VM* vm, ArgsView args){ \
T& self = _CAST(T&, args[0]); \
return VAR(self->get_##NAME()); \
}, \
[](VM* vm, ArgsView args){ \
T& self = _CAST(T&, args[0]); \
using __NT = decltype(self->get_##NAME()); \
self->set_##NAME(CAST(__NT, args[1])); \
return vm->None; \
}));
#define PK_REGISTER_READONLY_PROPERTY(T, NAME) \
type->attr().set(#NAME, vm->property( \
[](VM* vm, ArgsView args){ \
T& self = _CAST(T&, args[0]); \
return VAR(self->get_##NAME()); \
}));
} // namespace pkpy

View File

@ -166,55 +166,6 @@ std::enable_if_t<std::is_pod_v<T> && !std::is_pointer_v<T>, PyObject*> py_var(VM
return VAR_T(C99Struct, std::monostate(), data);
}
/*****************************************************************/
struct NativeProxyFuncCBase {
virtual PyObject* operator()(VM* vm, ArgsView args) = 0;
static void check_args_size(VM* vm, ArgsView args, int n){
if (args.size() != n){
vm->TypeError("expected " + std::to_string(n) + " arguments, got " + std::to_string(args.size()));
}
}
};
template<typename Ret, typename... Params>
struct NativeProxyFuncC final: NativeProxyFuncCBase {
static constexpr int N = sizeof...(Params);
using _Fp = Ret(*)(Params...);
_Fp func;
NativeProxyFuncC(_Fp func) : func(func) {}
PyObject* operator()(VM* vm, ArgsView args) override {
check_args_size(vm, args, N);
return call<Ret>(vm, args, std::make_index_sequence<N>());
}
template<typename __Ret, size_t... Is>
PyObject* call(VM* vm, ArgsView args, std::index_sequence<Is...>){
if constexpr(std::is_void_v<__Ret>){
func(py_cast<Params>(vm, args[Is])...);
return vm->None;
}else{
__Ret ret = func(py_cast<Params>(vm, args[Is])...);
return VAR(std::move(ret));
}
}
};
inline PyObject* _any_c_wrapper(VM* vm, ArgsView args){
NativeProxyFuncCBase* pf = lambda_get_userdata<NativeProxyFuncCBase*>(args.begin());
return (*pf)(vm, args);
}
template<typename T>
void bind_any_c_fp(VM* vm, PyObject* obj, Str name, T fp){
static_assert(std::is_pod_v<T>);
static_assert(std::is_pointer_v<T>);
auto proxy = new NativeProxyFuncC(fp);
PyObject* func = VAR(NativeFunc(_any_c_wrapper, proxy->N, false));
_CAST(NativeFunc&, func).set_userdata(proxy);
obj->attr().set(name, func);
}
void add_module_c(VM* vm);
} // namespace pkpy

View File

@ -14,6 +14,7 @@
#include "vm.h"
#include "re.h"
#include "random.h"
#include "bindings.h"
namespace pkpy {

View File

@ -451,10 +451,10 @@ public:
PyObject* _run_top_frame();
void post_init();
PyObject* _py_generator(Frame&& frame, ArgsView buffer);
// new style binding api
PyObject* bind(PyObject*, const char*, const char*, NativeFuncC);
PyObject* bind(PyObject*, const char*, NativeFuncC);
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);
};
DEF_NATIVE_2(Str, tp_str)

View File

@ -956,17 +956,16 @@ void VM::setattr(PyObject* obj, StrName name, PyObject* value){
obj->attr().set(name, value);
}
PyObject* VM::bind(PyObject* obj, const char* sig, NativeFuncC fn){
return bind(obj, sig, nullptr, fn);
PyObject* VM::bind(PyObject* obj, const char* sig, NativeFuncC fn, void* userdata){
return bind(obj, sig, nullptr, fn, userdata);
}
PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, NativeFuncC fn){
PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, NativeFuncC fn, void* userdata){
CodeObject_ co;
try{
// fn(a, b, *c, d=1) -> None
co = compile("def " + Str(sig) + " : pass", "<bind>", EXEC_MODE);
}catch(Exception& e){
PK_UNUSED(e);
}catch(Exception&){
throw std::runtime_error("invalid signature: " + std::string(sig));
}
if(co->func_decls.size() != 1){
@ -978,6 +977,9 @@ 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);
return f_obj;
}

View File

@ -10,7 +10,7 @@ std::string f_input(){
int main(int argc, char** argv){
pkpy::VM* vm = pkpy_new_vm();
pkpy::bind_any_c_fp(vm, vm->builtins, "input", &f_input);
pkpy::_bind(vm, vm->builtins, "input() -> str", &f_input);
if(argc == 1){
pkpy::REPL* repl = pkpy_new_repl(vm);