From f16f98fcf87cb9a7ef21775481b73a43f09a9b8a Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sat, 5 Aug 2023 15:44:23 +0800 Subject: [PATCH] ... --- docs/modules/box2d.md | 4 +- docs/quick-start/bind.md | 21 +++---- include/pocketpy/bindings.h | 109 ++++++++++++------------------------ include/pocketpy/obj.h | 4 +- include/pocketpy/str.h | 2 + include/pocketpy/vm.h | 3 +- src/linalg.cpp | 10 ++-- src/pocketpy.cpp | 96 +++++++++++-------------------- src/vm.cpp | 20 ++++--- tests/99_bugs.py | 2 +- 10 files changed, 104 insertions(+), 167 deletions(-) diff --git a/docs/modules/box2d.md b/docs/modules/box2d.md index 06340152..92319377 100644 --- a/docs/modules/box2d.md +++ b/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: diff --git a/docs/quick-start/bind.md b/docs/quick-start/bind.md index f0ddc743..6108e5f6 100644 --- a/docs/quick-start/bind.md +++ b/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; + }); } }; ``` diff --git a/include/pocketpy/bindings.h b/include/pocketpy/bindings.h index 1d6905d5..aa1ef5d9 100644 --- a/include/pocketpy/bindings.h +++ b/include/pocketpy/bindings.h @@ -65,33 +65,6 @@ struct NativeProxyMethodC final: NativeProxyFuncCBase { } }; -template -struct NativeProxyOpaqueMethodC final: NativeProxyFuncCBase { - static_assert(std::is_base_of_v, _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(vm, args, std::make_index_sequence()); - } - - template - PyObject* call(VM* vm, ArgsView args, std::index_sequence){ - OpaquePointer& _opa_self = py_cast<_OpaqueT&>(vm, args[0]); - T& self = *_opa_self.ptr; - if constexpr(std::is_void_v<__Ret>){ - (self.*func)(py_cast(vm, args[Is+1])...); - return vm->None; - }else{ - __Ret ret = (self.*func)(py_cast(vm, args[Is+1])...); - return VAR(std::move(ret)); - } - } -}; - inline PyObject* proxy_wrapper(VM* vm, ArgsView args){ NativeProxyFuncCBase* pf = lambda_get_userdata(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(func); vm->bind(obj, sig, proxy_wrapper, proxy); } - -template -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_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) \ - type->attr().set(#NAME, vm->property( \ - [](VM* vm, ArgsView args){ \ - T& self = _CAST(T&, args[0]); \ - return VAR(self->NAME); \ - })); +#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, __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_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, __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_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 \ No newline at end of file diff --git a/include/pocketpy/obj.h b/include/pocketpy/obj.h index c3f00da7..b59871f5 100644 --- a/include/pocketpy/obj.h +++ b/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 { diff --git a/include/pocketpy/str.h b/include/pocketpy/str.h index 4d0a6c82..a13c97c3 100644 --- a/include/pocketpy/str.h +++ b/include/pocketpy/str.h @@ -3,6 +3,7 @@ #include "common.h" #include "memory.h" #include "vector.h" +#include 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); diff --git a/include/pocketpy/vm.h b/include/pocketpy/vm.h index 1b2457e0..3fd67e05 100644 --- a/include/pocketpy/vm.h +++ b/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) diff --git a/src/linalg.cpp b/src/linalg.cpp index 272c222e..911ba07d 100644 --- a/src/linalg.cpp +++ b/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) diff --git a/src/pocketpy.cpp b/src/pocketpy.cpp index e65b457c..b1c5af53 100644 --- a/src/pocketpy.cpp +++ b/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){ - return CAST(Slice&, args[0]).start; - })); - _t(tp_slice)->attr().set("stop", property([](VM* vm, ArgsView args){ - return CAST(Slice&, args[0]).stop; - })); - _t(tp_slice)->attr().set("step", property([](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_slice), "start", [](VM* vm, ArgsView args){ + return CAST(Slice&, args[0]).start; + }); + bind_property(_t(tp_slice), "stop", [](VM* vm, ArgsView args){ + return CAST(Slice&, args[0]).stop; + }); + bind_property(_t(tp_slice), "step", [](VM* vm, ArgsView args){ + return CAST(Slice&, args[0]).step; + }); + + 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); diff --git a/src/vm.cpp b/src/vm.cpp index 21b3860c..062d4cce 100644 --- a/src/vm.cpp +++ b/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(tp_native_func, fget, 1, false); - PyObject* _1 = vm->None; - if(fset != nullptr) _1 = heap.gcnew(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(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(tp_native_func, fget, 1, false); + PyObject* _1 = vm->None; + if(fset != nullptr) _1 = heap.gcnew(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; } diff --git a/tests/99_bugs.py b/tests/99_bugs.py index f69d967d..9e259a8b 100644 --- a/tests/99_bugs.py +++ b/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