blueloveTH 2 rokov pred
rodič
commit
53d272ce2f

+ 1 - 1
amalgamate.py

@@ -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 - 0
include/pocketpy/bindings.h

@@ -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

+ 0 - 49
include/pocketpy/cffi.h

@@ -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

+ 1 - 0
include/pocketpy/pocketpy.h

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

+ 3 - 3
include/pocketpy/vm.h

@@ -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)

+ 7 - 5
src/vm.cpp

@@ -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;
 }

+ 1 - 1
src2/main.cpp

@@ -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);