blueloveTH 2 лет назад
Родитель
Сommit
f16f98fcf8

+ 2 - 2
docs/modules/box2d.md

@@ -122,8 +122,8 @@ class Body:
     def apply_force(self, force: vec2, point: vec2): ...
     def apply_force_to_center(self, force: vec2): ...
     def apply_torque(self, torque: float): ...
-    def apply_linear_impulse(self, impulse: vec2, point: vec2): ...
-    def apply_linear_impulse_to_center(self, impulse: vec2): ...
+    def apply_impulse(self, impulse: vec2, point: vec2): ...
+    def apply_impulse_to_center(self, impulse: vec2): ...
     def apply_angular_impulse(self, impulse: float): ...
 
     def get_node(self) -> _NodeLike:

+ 11 - 10
docs/quick-start/bind.md

@@ -67,7 +67,7 @@ a property is a python's `property` that attached to a type instance with a gett
 
 You can use `@property` to create python property or use `vm->property` to create native property.
 
-You can also use `vm->bind_property()`, the new style property binding function.
+Use `vm->bind_property()`, the new style property binding function.
 
 ```cpp
 struct Point {
@@ -86,15 +86,16 @@ struct Point {
     });
 
     // getter and setter of property `x`
-    type->attr().set("x", vm->property([](VM* vm, ArgsView args){
-        Point& self = CAST(Point&, args[0]);
-        return VAR(self.x);
-    },
-    [](VM* vm, ArgsView args){
-        Point& self = CAST(Point&, args[0]);
-        self.x = CAST(int, args[1]);
-        return vm->None;
-    }));
+    vm->bind_property(type, "x: int",
+      [](VM* vm, ArgsView args){
+          Point& self = CAST(Point&, args[0]);
+          return VAR(self.x);
+      },
+      [](VM* vm, ArgsView args){
+          Point& self = CAST(Point&, args[0]);
+          self.x = CAST(int, args[1]);
+          return vm->None;
+      });
   }
 };
 ```

+ 38 - 77
include/pocketpy/bindings.h

@@ -65,33 +65,6 @@ struct NativeProxyMethodC final: NativeProxyFuncCBase {
     }
 };
 
-template<typename _OpaqueT, typename Ret, typename T, typename... Params>
-struct NativeProxyOpaqueMethodC final: NativeProxyFuncCBase {
-    static_assert(std::is_base_of_v<OpaquePointer<T>, _OpaqueT>);
-    static constexpr int N = sizeof...(Params);
-    using _Fp = Ret(T::*)(Params...);
-    _Fp func;
-    NativeProxyOpaqueMethodC(_Fp func) : func(func) {}
-
-    PyObject* operator()(VM* vm, ArgsView args) override {
-        PK_ASSERT(args.size() == N+1);
-        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...>){
-        OpaquePointer<T>& _opa_self = py_cast<_OpaqueT&>(vm, args[0]);
-        T& self = *_opa_self.ptr;
-        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);
@@ -108,56 +81,44 @@ 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 _OpaqueT, typename Ret, typename T, typename... Params>
-void _bind_opaque(VM* vm, PyObject* obj, const char* sig, Ret(T::*func)(Params...)){
-    auto proxy = new NativeProxyOpaqueMethodC<_OpaqueT, Ret, T, Params...>(func);
-    vm->bind(obj, sig, proxy_wrapper, proxy);
-}
 /*****************************************************************/
-#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, __tp)   \
-        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;    \
-            }, __tp));
-
-#define PK_REGISTER_READONLY_PROPERTY(T, NAME, __tp)   \
-        type->attr().set(#NAME, vm->property(   \
-            [](VM* vm, ArgsView args){  \
-                T& self = _CAST(T&, args[0]);   \
-                return VAR(self->get_##NAME()); \
-            }, nullptr, __tp));
-
-#define PK_REGISTER_CONSTRUCTOR(T, T0)  \
-        vm->bind_constructor<2>(type, [](VM* vm, ArgsView args){ \
-            void* p = CAST(void*, args[0]); \
-            return VAR_T(T, (T0*)p);    \
-        });
+#define PK_REGISTER_FIELD(T, NAME, REF, EXPR)       \
+        vm->bind_property(type, NAME,               \
+            [](VM* vm, ArgsView args){              \
+                T& self = _CAST(T&, args[0]);       \
+                return VAR(self.REF().EXPR);        \
+            },                                      \
+            [](VM* vm, ArgsView args){              \
+                T& self = _CAST(T&, args[0]);       \
+                self.REF().EXPR = CAST(decltype(self.REF().EXPR), args[1]);     \
+                return vm->None;                                                \
+            });
+
+#define PK_REGISTER_READONLY_FIELD(T, NAME, REF, EXPR)          \
+        vm->bind_property(type, NAME,                           \
+            [](VM* vm, ArgsView args){              \
+                T& self = _CAST(T&, args[0]);       \
+                return VAR(self.REF().EXPR);        \
+            });
+
+#define PK_REGISTER_PROPERTY(T, NAME, REF, FGET, FSET)  \
+        vm->bind_property(type, NAME,                   \
+            [](VM* vm, ArgsView args){                  \
+                T& self = _CAST(T&, args[0]);           \
+                return VAR(self.REF().FGET());          \
+            },                                          \
+            [](VM* vm, ArgsView args){                  \
+                T& self = _CAST(T&, args[0]);           \
+                using __NT = decltype(self.REF().FGET());   \
+                self.REF().FSET(CAST(__NT, args[1]));       \
+                return vm->None;                            \
+            });
+
+#define PK_REGISTER_READONLY_PROPERTY(T, NAME, REF, FGET)  \
+        vm->bind_property(type, NAME,                   \
+            [](VM* vm, ArgsView args){                  \
+                T& self = _CAST(T&, args[0]);           \
+                return VAR(self.REF().FGET());          \
+            });
 
 }   // namespace pkpy

+ 2 - 2
include/pocketpy/obj.h

@@ -31,8 +31,8 @@ struct BoundMethod {
 struct Property{
     PyObject* getter;
     PyObject* setter;
-    const char* type_hint;
-    Property(PyObject* getter, PyObject* setter, const char* type_hint) : getter(getter), setter(setter), type_hint(type_hint) {}
+    Str type_hint;
+    Property(PyObject* getter, PyObject* setter, Str type_hint) : getter(getter), setter(setter), type_hint(type_hint) {}
 };
 
 struct Range {

+ 2 - 0
include/pocketpy/str.h

@@ -3,6 +3,7 @@
 #include "common.h"
 #include "memory.h"
 #include "vector.h"
+#include <cstddef>
 
 namespace pkpy {
 
@@ -22,6 +23,7 @@ struct Str{
     Str(int size, bool is_ascii);
     Str(const std::string& s);
     Str(std::string_view s);
+    Str(std::nullptr_t) { FATAL_ERROR(); }
     Str(const char* s);
     Str(const char* s, int len);
     Str(const Str& other);

+ 1 - 2
include/pocketpy/vm.h

@@ -203,7 +203,6 @@ public:
         return call_method(self, callable, args...);
     }
 
-    PyObject* property(NativeFuncC fget, NativeFuncC fset=nullptr, const char* type_hint=nullptr);
     PyObject* new_type_object(PyObject* mod, StrName name, Type base, bool subclass_enabled=true);
     Type _new_type_object(StrName name, Type base=0);
     PyObject* _find_type_object(const Str& type);
@@ -462,7 +461,7 @@ public:
     // new style binding api
     PyObject* bind(PyObject*, const char*, const char*, NativeFuncC, UserData userdata={});
     PyObject* bind(PyObject*, const char*, NativeFuncC, UserData userdata={});
-    PyObject* bind_property(PyObject*, StrName name, const char* type_hint, NativeFuncC fget, NativeFuncC fset=nullptr);
+    PyObject* bind_property(PyObject*, Str, NativeFuncC fget, NativeFuncC fset=nullptr);
 };
 
 DEF_NATIVE_2(Str, tp_str)

+ 6 - 4
src/linalg.cpp

@@ -36,14 +36,15 @@ namespace pkpy{
         });
 
 #define BIND_VEC_FIELD(D, name)  \
-        type->attr().set(#name, vm->property([](VM* vm, ArgsView args){     \
+        vm->bind_property(type, #name,                                      \
+        [](VM* vm, ArgsView args){                                          \
             PyVec##D& self = _CAST(PyVec##D&, args[0]);                     \
             return VAR(self.name);                                          \
         }, [](VM* vm, ArgsView args){                                       \
             PyVec##D& self = _CAST(PyVec##D&, args[0]);                     \
             self.name = CAST(f64, args[1]);                                 \
             return vm->None;                                                \
-        }));
+        });
 
 
     void PyVec2::_register(VM* vm, PyObject* mod, PyObject* type){
@@ -284,14 +285,15 @@ namespace pkpy{
         });
 
 #define PROPERTY_FIELD(field) \
-        type->attr().set(#field, vm->property([](VM* vm, ArgsView args){    \
+        vm->bind_property(type, #field ": float", \
+        [](VM* vm, ArgsView args){      \
             PyMat3x3& self = _CAST(PyMat3x3&, args[0]);                     \
             return VAR(self.field);                                         \
         }, [](VM* vm, ArgsView args){                                       \
             PyMat3x3& self = _CAST(PyMat3x3&, args[0]);                     \
             self.field = CAST(f64, args[1]);                                \
             return vm->None;                                                \
-        }));
+        });
 
         PROPERTY_FIELD(_11)
         PROPERTY_FIELD(_12)

+ 30 - 60
src/pocketpy.cpp

@@ -149,36 +149,6 @@ void init_builtins(VM* _vm) {
         }
     });
 
-    _vm->bind_builtin_func<3>("pow", [](VM* vm, ArgsView args) {
-        i64 lhs = CAST(i64, args[0]);   // assume lhs>=0
-        i64 rhs = CAST(i64, args[1]);   // assume rhs>=0
-        i64 mod = CAST(i64, args[2]);   // assume mod>0, mod*mod should not overflow
-
-        if(rhs <= 0){
-            vm->ValueError("pow(): rhs should be positive");
-        }
-
-        PK_LOCAL_STATIC const auto _mul = [](i64 a, i64 b, i64 c){
-            if(c < 16384) return (a%c) * (b%c) % c;
-            i64 res = 0;
-            while(b > 0){
-                if(b & 1) res = (res + a) % c;
-                a = (a << 1) % c;
-                b >>= 1;
-            }
-            return res;
-        };
-
-        i64 res = 1;
-        lhs %= mod;
-        while(rhs){
-            if(rhs & 1) res = _mul(res, lhs, mod);
-            lhs = _mul(lhs, lhs, mod);
-            rhs >>= 1;
-        }
-        return VAR(res);
-    });
-
     _vm->bind_builtin_func<1>("id", [](VM* vm, ArgsView args) {
         PyObject* obj = args[0];
         if(is_tagged(obj)) return vm->None;
@@ -1216,41 +1186,41 @@ void init_builtins(VM* _vm) {
     /************ property ************/
     _vm->bind_constructor<-1>("property", [](VM* vm, ArgsView args) {
         if(args.size() == 1+1){
-            return VAR(Property(args[1], vm->None, nullptr));
+            return VAR(Property(args[1], vm->None, ""));
         }else if(args.size() == 1+2){
-            return VAR(Property(args[1], args[2], nullptr));
+            return VAR(Property(args[1], args[2], ""));
         }
         vm->TypeError("property() takes at most 2 arguments");
         return vm->None;
     });
 
-    _vm->bind_property(_vm->_t(_vm->tp_property), "type_hint", "str", [](VM* vm, ArgsView args){
+    _vm->bind_property(_vm->_t(_vm->tp_property), "type_hint: str", [](VM* vm, ArgsView args){
         Property& self = _CAST(Property&, args[0]);
-        if(self.type_hint == nullptr) return vm->None;
         return VAR(self.type_hint);
     });
     
-    _vm->_t(_vm->tp_function)->attr().set("__doc__", _vm->property([](VM* vm, ArgsView args) {
+
+    _vm->bind_property(_vm->_t(_vm->tp_function), "__doc__", [](VM* vm, ArgsView args) {
         Function& func = _CAST(Function&, args[0]);
         return VAR(func.decl->docstring);
-    }));
+    });
 
-    _vm->_t(_vm->tp_native_func)->attr().set("__doc__", _vm->property([](VM* vm, ArgsView args) {
+    _vm->bind_property(_vm->_t(_vm->tp_native_func), "__doc__", [](VM* vm, ArgsView args) {
         NativeFunc& func = _CAST(NativeFunc&, args[0]);
         if(func.decl != nullptr) return VAR(func.decl->docstring);
         return VAR("");
-    }));
+    });
 
-    _vm->_t(_vm->tp_function)->attr().set("__signature__", _vm->property([](VM* vm, ArgsView args) {
+    _vm->bind_property(_vm->_t(_vm->tp_function), "__signature__", [](VM* vm, ArgsView args) {
         Function& func = _CAST(Function&, args[0]);
         return VAR(func.decl->signature);
-    }));
+    });
 
-    _vm->_t(_vm->tp_native_func)->attr().set("__signature__", _vm->property([](VM* vm, ArgsView args) {
+    _vm->bind_property(_vm->_t(_vm->tp_native_func), "__signature__", [](VM* vm, ArgsView args) {
         NativeFunc& func = _CAST(NativeFunc&, args[0]);
         if(func.decl != nullptr) return VAR(func.decl->signature);
         return VAR("unknown(*args, **kwargs)");
-    }));
+    });
 
     RangeIter::register_class(_vm, _vm->builtins);
     ArrayIter::register_class(_vm, _vm->builtins);
@@ -1520,41 +1490,41 @@ void add_module_gc(VM* vm){
 void VM::post_init(){
     init_builtins(this);
 
-    _t(tp_object)->attr().set("__class__", property(PK_LAMBDA(vm->_t(args[0]))));
-    _t(tp_type)->attr().set("__base__", property([](VM* vm, ArgsView args){
+    bind_property(_t(tp_object), "__class__", PK_LAMBDA(VAR(vm->_t(args[0]))));
+    bind_property(_t(tp_type), "__base__", [](VM* vm, ArgsView args){
         const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, args[0])];
         return info.base.index == -1 ? vm->None : vm->_all_types[info.base].obj;
-    }));
-    _t(tp_type)->attr().set("__name__", property([](VM* vm, ArgsView args){
+    });
+    bind_property(_t(tp_type), "__name__", [](VM* vm, ArgsView args){
         const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, args[0])];
         return VAR(info.name);
-    }));
-
-    _t(tp_bound_method)->attr().set("__self__", property([](VM* vm, ArgsView args){
+    });
+    bind_property(_t(tp_bound_method), "__self__", [](VM* vm, ArgsView args){
         return CAST(BoundMethod&, args[0]).self;
-    }));
-    _t(tp_bound_method)->attr().set("__func__", property([](VM* vm, ArgsView args){
+    });
+    bind_property(_t(tp_bound_method), "__func__", [](VM* vm, ArgsView args){
         return CAST(BoundMethod&, args[0]).func;
-    }));
+    });
 
     bind__eq__(tp_bound_method, [](VM* vm, PyObject* lhs, PyObject* rhs){
         if(!is_non_tagged_type(rhs, vm->tp_bound_method)) return vm->NotImplemented;
         return VAR(_CAST(BoundMethod&, lhs) == _CAST(BoundMethod&, rhs));
     });
-    _t(tp_slice)->attr().set("start", property([](VM* vm, ArgsView args){
+
+    bind_property(_t(tp_slice), "start", [](VM* vm, ArgsView args){
         return CAST(Slice&, args[0]).start;
-    }));
-    _t(tp_slice)->attr().set("stop", property([](VM* vm, ArgsView args){
+    });
+    bind_property(_t(tp_slice), "stop", [](VM* vm, ArgsView args){
         return CAST(Slice&, args[0]).stop;
-    }));
-    _t(tp_slice)->attr().set("step", property([](VM* vm, ArgsView args){
+    });
+    bind_property(_t(tp_slice), "step", [](VM* vm, ArgsView args){
         return CAST(Slice&, args[0]).step;
-    }));
+    });
 
-    _t(tp_object)->attr().set("__dict__", property([](VM* vm, ArgsView args){
+    bind_property(_t(tp_object), "__dict__", [](VM* vm, ArgsView args){
         if(is_tagged(args[0]) || !args[0]->is_attr_valid()) return vm->None;
         return VAR(MappingProxy(args[0]));
-    }));
+    });
 
 #if !PK_DEBUG_NO_BUILTINS
     add_module_sys(this);

+ 11 - 9
src/vm.cpp

@@ -113,13 +113,6 @@ namespace pkpy{
         return nullptr;
     }
 
-    PyObject* VM::property(NativeFuncC fget, NativeFuncC fset, const char* type_hint){
-        PyObject* _0 = heap.gcnew<NativeFunc>(tp_native_func, fget, 1, false);
-        PyObject* _1 = vm->None;
-        if(fset != nullptr) _1 = heap.gcnew<NativeFunc>(tp_native_func, fset, 2, false);
-        return VAR(Property(_0, _1, type_hint));
-    }
-
     PyObject* VM::new_type_object(PyObject* mod, StrName name, Type base, bool subclass_enabled){
         PyObject* obj = heap._new<Type>(tp_type, _all_types.size());
         const PyTypeInfo& base_info = _all_types[base];
@@ -979,8 +972,17 @@ PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Native
     return f_obj;
 }
 
-PyObject* VM::bind_property(PyObject* obj, StrName name, const char* type_hint, NativeFuncC fget, NativeFuncC fset){
-    PyObject* prop = property(fget, fset, type_hint);
+PyObject* VM::bind_property(PyObject* obj, Str name, NativeFuncC fget, NativeFuncC fset){
+    PyObject* _0 = heap.gcnew<NativeFunc>(tp_native_func, fget, 1, false);
+    PyObject* _1 = vm->None;
+    if(fset != nullptr) _1 = heap.gcnew<NativeFunc>(tp_native_func, fset, 2, false);
+    Str type_hint;
+    int pos = name.index(":");
+    if(pos > 0){
+        type_hint = name.substr(pos + 1).strip();
+        name = name.substr(0, pos).strip();
+    }
+    PyObject* prop = VAR(Property(_0, _1, type_hint));
     obj->attr().set(name, prop);
     return prop;
 }

+ 1 - 1
tests/99_bugs.py

@@ -31,7 +31,7 @@ if inq is   not 1:
 if inq  is  not  0:
     assert False
 
-assert pow(2,5000,2**59-1) == 17592186044416
+# assert pow(2,5000,2**59-1) == 17592186044416
 
 def g(x):
     return x