mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 11:30:18 +00:00
...
This commit is contained in:
parent
15b92d5fb4
commit
53d272ce2f
@ -9,7 +9,7 @@ pipeline = [
|
|||||||
["config.h", "common.h", "memory.h", "vector.h", "str.h", "tuplelist.h", "namedict.h", "error.h", "lexer.h"],
|
["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"],
|
["obj.h", "dict.h", "codeobject.h", "frame.h"],
|
||||||
["gc.h", "vm.h", "ceval.h", "expr.h", "compiler.h", "repl.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"]
|
["export.h", "pocketpy.h"]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
125
include/pocketpy/bindings.h
Normal file
125
include/pocketpy/bindings.h
Normal 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
|
@ -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);
|
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);
|
void add_module_c(VM* vm);
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
@ -14,6 +14,7 @@
|
|||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
#include "re.h"
|
#include "re.h"
|
||||||
#include "random.h"
|
#include "random.h"
|
||||||
|
#include "bindings.h"
|
||||||
|
|
||||||
namespace pkpy {
|
namespace pkpy {
|
||||||
|
|
||||||
|
@ -451,10 +451,10 @@ public:
|
|||||||
PyObject* _run_top_frame();
|
PyObject* _run_top_frame();
|
||||||
void post_init();
|
void post_init();
|
||||||
PyObject* _py_generator(Frame&& frame, ArgsView buffer);
|
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_&);
|
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)
|
DEF_NATIVE_2(Str, tp_str)
|
||||||
|
12
src/vm.cpp
12
src/vm.cpp
@ -956,17 +956,16 @@ void VM::setattr(PyObject* obj, StrName name, PyObject* value){
|
|||||||
obj->attr().set(name, value);
|
obj->attr().set(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject* VM::bind(PyObject* obj, const char* sig, NativeFuncC fn){
|
PyObject* VM::bind(PyObject* obj, const char* sig, NativeFuncC fn, void* userdata){
|
||||||
return bind(obj, sig, nullptr, fn);
|
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;
|
CodeObject_ co;
|
||||||
try{
|
try{
|
||||||
// fn(a, b, *c, d=1) -> None
|
// fn(a, b, *c, d=1) -> None
|
||||||
co = compile("def " + Str(sig) + " : pass", "<bind>", EXEC_MODE);
|
co = compile("def " + Str(sig) + " : pass", "<bind>", EXEC_MODE);
|
||||||
}catch(Exception& e){
|
}catch(Exception&){
|
||||||
PK_UNUSED(e);
|
|
||||||
throw std::runtime_error("invalid signature: " + std::string(sig));
|
throw std::runtime_error("invalid signature: " + std::string(sig));
|
||||||
}
|
}
|
||||||
if(co->func_decls.size() != 1){
|
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();
|
decl->docstring = Str(docstring).strip();
|
||||||
}
|
}
|
||||||
PyObject* f_obj = VAR(NativeFunc(fn, decl));
|
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);
|
obj->attr().set(decl->code->name, f_obj);
|
||||||
return f_obj;
|
return f_obj;
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ std::string f_input(){
|
|||||||
int main(int argc, char** argv){
|
int main(int argc, char** argv){
|
||||||
pkpy::VM* vm = pkpy_new_vm();
|
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){
|
if(argc == 1){
|
||||||
pkpy::REPL* repl = pkpy_new_repl(vm);
|
pkpy::REPL* repl = pkpy_new_repl(vm);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user