This commit is contained in:
BLUELOVETH 2023-08-02 14:38:00 +08:00
parent f0ca29a30a
commit 26fe69da28
6 changed files with 26 additions and 10 deletions

View File

@ -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 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 ```cpp
struct Point { struct Point {
PY_CLASS(Point, test, Point); PY_CLASS(Point, test, Point);

View File

@ -134,7 +134,7 @@ void _bind_opaque(VM* vm, PyObject* obj, const char* sig, Ret(T::*func)(Params..
return VAR(self->NAME); \ return VAR(self->NAME); \
})); }));
#define PK_REGISTER_PROPERTY(T, NAME) \ #define PK_REGISTER_PROPERTY(T, NAME, __tp) \
type->attr().set(#NAME, vm->property( \ type->attr().set(#NAME, vm->property( \
[](VM* vm, ArgsView args){ \ [](VM* vm, ArgsView args){ \
T& self = _CAST(T&, args[0]); \ 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()); \ using __NT = decltype(self->get_##NAME()); \
self->set_##NAME(CAST(__NT, args[1])); \ self->set_##NAME(CAST(__NT, args[1])); \
return vm->None; \ 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( \ type->attr().set(#NAME, vm->property( \
[](VM* vm, ArgsView args){ \ [](VM* vm, ArgsView args){ \
T& self = _CAST(T&, args[0]); \ T& self = _CAST(T&, args[0]); \
return VAR(self->get_##NAME()); \ return VAR(self->get_##NAME()); \
})); }, nullptr, #__tp));
#define PK_REGISTER_CONSTRUCTOR(T, T0) \ #define PK_REGISTER_CONSTRUCTOR(T, T0) \
vm->bind_constructor<2>(type, [](VM* vm, ArgsView args){ \ vm->bind_constructor<2>(type, [](VM* vm, ArgsView args){ \

View File

@ -31,7 +31,8 @@ struct BoundMethod {
struct Property{ struct Property{
PyObject* getter; PyObject* getter;
PyObject* setter; 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 { struct Range {

View File

@ -201,7 +201,7 @@ public:
return call_method(self, callable, args...); 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); PyObject* new_type_object(PyObject* mod, StrName name, Type base, bool subclass_enabled=true);
Type _new_type_object(StrName name, Type base=0); Type _new_type_object(StrName name, Type base=0);
PyObject* _find_type_object(const Str& type); PyObject* _find_type_object(const Str& type);
@ -460,6 +460,7 @@ public:
// new style binding api // new style binding api
PyObject* bind(PyObject*, const char*, const char*, NativeFuncC, UserData userdata={}); PyObject* bind(PyObject*, const char*, const char*, NativeFuncC, UserData userdata={});
PyObject* bind(PyObject*, 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) DEF_NATIVE_2(Str, tp_str)

View File

@ -1190,14 +1190,20 @@ void init_builtins(VM* _vm) {
/************ property ************/ /************ property ************/
_vm->bind_constructor<-1>("property", [](VM* vm, ArgsView args) { _vm->bind_constructor<-1>("property", [](VM* vm, ArgsView args) {
if(args.size() == 1+1){ 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){ }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"); vm->TypeError("property() takes at most 2 arguments");
return vm->None; 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) { _vm->_t(_vm->tp_function)->attr().set("__doc__", _vm->property([](VM* vm, ArgsView args) {
Function& func = _CAST(Function&, args[0]); Function& func = _CAST(Function&, args[0]);
return VAR(func.decl->docstring); return VAR(func.decl->docstring);

View File

@ -113,11 +113,11 @@ namespace pkpy{
return nullptr; 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* _0 = heap.gcnew(tp_native_func, NativeFunc(fget, 1, false));
PyObject* _1 = vm->None; PyObject* _1 = vm->None;
if(fset != nullptr) _1 = heap.gcnew(tp_native_func, NativeFunc(fset, 2, false)); 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){ 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; 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){ void VM::_error(Exception e){
if(callstack.empty()){ if(callstack.empty()){
e.is_re = false; e.is_re = false;