BLUELOVETH 2 years ago
parent
commit
26fe69da28
6 changed files with 26 additions and 10 deletions
  1. 2 0
      docs/quick-start/bind.md
  2. 4 4
      include/pocketpy/bindings.h
  3. 2 1
      include/pocketpy/obj.h
  4. 2 1
      include/pocketpy/vm.h
  5. 8 2
      src/pocketpy.cpp
  6. 8 2
      src/vm.cpp

+ 2 - 0
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);

+ 4 - 4
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){ \

+ 2 - 1
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 {

+ 2 - 1
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)

+ 8 - 2
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]);

+ 8 - 2
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;