From 26fe69da2855491831d2767f7861d0bd5550ac9b Mon Sep 17 00:00:00 2001 From: BLUELOVETH Date: Wed, 2 Aug 2023 14:38:00 +0800 Subject: [PATCH] ... --- docs/quick-start/bind.md | 2 ++ include/pocketpy/bindings.h | 8 ++++---- include/pocketpy/obj.h | 3 ++- include/pocketpy/vm.h | 3 ++- src/pocketpy.cpp | 10 ++++++++-- src/vm.cpp | 10 ++++++++-- 6 files changed, 26 insertions(+), 10 deletions(-) diff --git a/docs/quick-start/bind.md b/docs/quick-start/bind.md index 10978b02..f0ddc743 100644 --- a/docs/quick-start/bind.md +++ b/docs/quick-start/bind.md @@ -67,6 +67,8 @@ 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. + ```cpp struct Point { PY_CLASS(Point, test, Point); diff --git a/include/pocketpy/bindings.h b/include/pocketpy/bindings.h index 52060267..caa02fd9 100644 --- a/include/pocketpy/bindings.h +++ b/include/pocketpy/bindings.h @@ -134,7 +134,7 @@ void _bind_opaque(VM* vm, PyObject* obj, const char* sig, Ret(T::*func)(Params.. return VAR(self->NAME); \ })); -#define PK_REGISTER_PROPERTY(T, NAME) \ +#define PK_REGISTER_PROPERTY(T, NAME, __tp) \ type->attr().set(#NAME, vm->property( \ [](VM* vm, ArgsView args){ \ T& self = _CAST(T&, args[0]); \ @@ -145,14 +145,14 @@ void _bind_opaque(VM* vm, PyObject* obj, const char* sig, Ret(T::*func)(Params.. using __NT = decltype(self->get_##NAME()); \ self->set_##NAME(CAST(__NT, args[1])); \ return vm->None; \ - })); + }, #__tp)); -#define PK_REGISTER_READONLY_PROPERTY(T, NAME) \ +#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){ \ diff --git a/include/pocketpy/obj.h b/include/pocketpy/obj.h index 54cf7484..12cdf9a7 100644 --- a/include/pocketpy/obj.h +++ b/include/pocketpy/obj.h @@ -31,7 +31,8 @@ struct BoundMethod { struct Property{ PyObject* getter; PyObject* setter; - Property(PyObject* getter, PyObject* setter) : getter(getter), setter(setter) {} + const char* type_hint; + Property(PyObject* getter, PyObject* setter, const char* type_hint) : getter(getter), setter(setter), type_hint(type_hint) {} }; struct Range { diff --git a/include/pocketpy/vm.h b/include/pocketpy/vm.h index 6bcb4b33..adde17e3 100644 --- a/include/pocketpy/vm.h +++ b/include/pocketpy/vm.h @@ -201,7 +201,7 @@ public: return call_method(self, callable, args...); } - PyObject* property(NativeFuncC fget, NativeFuncC fset=nullptr); + 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); @@ -460,6 +460,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); }; DEF_NATIVE_2(Str, tp_str) diff --git a/src/pocketpy.cpp b/src/pocketpy.cpp index 3fd9d506..12f3b5bd 100644 --- a/src/pocketpy.cpp +++ b/src/pocketpy.cpp @@ -1190,13 +1190,19 @@ 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)); + return VAR(Property(args[1], vm->None, nullptr)); }else if(args.size() == 1+2){ - return VAR(Property(args[1], args[2])); + return VAR(Property(args[1], args[2], nullptr)); } 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){ + 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) { Function& func = _CAST(Function&, args[0]); diff --git a/src/vm.cpp b/src/vm.cpp index 0803e647..8381dc1a 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -113,11 +113,11 @@ namespace pkpy{ return nullptr; } - PyObject* VM::property(NativeFuncC fget, NativeFuncC fset){ + PyObject* VM::property(NativeFuncC fget, NativeFuncC fset, const char* type_hint){ PyObject* _0 = heap.gcnew(tp_native_func, NativeFunc(fget, 1, false)); PyObject* _1 = vm->None; if(fset != nullptr) _1 = heap.gcnew(tp_native_func, NativeFunc(fset, 2, false)); - return call(_t(tp_property), _0, _1); + return VAR(Property(_0, _1, type_hint)); } PyObject* VM::new_type_object(PyObject* mod, StrName name, Type base, bool subclass_enabled){ @@ -979,6 +979,12 @@ 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); + obj->attr().set(name, prop); + return prop; +} + void VM::_error(Exception e){ if(callstack.empty()){ e.is_re = false;