reimpl property

This commit is contained in:
blueloveTH 2023-05-27 22:33:43 +08:00
parent 2e5c2b7147
commit e1eed59030
4 changed files with 36 additions and 38 deletions

View File

@ -129,28 +129,8 @@ def list@sort(self, reverse=False):
if reverse: if reverse:
self.reverse() self.reverse()
class property: def staticmethod(f):
def __init__(self, fget, fset=None): return f # no effect
self.fget = fget
self.fset = fset
def __get__(self, obj):
return self.fget(obj)
def __set__(self, obj, value):
if self.fset is None:
raise AttributeError("readonly property")
self.fset(obj, value)
class staticmethod:
def __init__(self, f):
self.f = f
def __get__(self, obj):
return self.f
def __call__(self, *args):
return self.f(*args)
def type@__repr__(self): def type@__repr__(self):
return "<class '" + self.__name__ + "'>" return "<class '" + self.__name__ + "'>"

View File

@ -89,6 +89,12 @@ struct BoundMethod {
} }
}; };
struct Property{
PyObject* getter;
PyObject* setter;
Property(PyObject* getter, PyObject* setter) : getter(getter), setter(setter) {}
};
struct Range { struct Range {
i64 start = 0; i64 start = 0;
i64 stop = -1; i64 stop = -1;

View File

@ -999,6 +999,16 @@ inline void init_builtins(VM* _vm) {
} }
return true; return true;
}); });
/************ property ************/
_vm->bind_constructor<-1>("property", [](VM* vm, ArgsView args) {
if(args.size() == 1+1){
return VAR(Property(args[1], vm->None));
}else if(args.size() == 1+2){
return VAR(Property(args[1], args[2]));
}
vm->TypeError("property() takes at most 2 arguments");
return vm->None;
});
RangeIter::register_class(_vm, _vm->builtins); RangeIter::register_class(_vm, _vm->builtins);
ArrayIter::register_class(_vm, _vm->builtins); ArrayIter::register_class(_vm, _vm->builtins);
@ -1324,7 +1334,7 @@ inline void VM::post_init(){
})); }));
_t(tp_object)->attr().set("__dict__", property([](VM* vm, ArgsView args){ _t(tp_object)->attr().set("__dict__", property([](VM* vm, ArgsView args){
if(is_tagged(args[0]) || !args[0]->is_attr_valid()) vm->AttributeError("__dict__"); if(is_tagged(args[0]) || !args[0]->is_attr_valid()) vm->AttributeError("'__dict__'");
return VAR(MappingProxy(args[0])); return VAR(MappingProxy(args[0]));
})); }));

View File

@ -133,7 +133,7 @@ public:
Type tp_function, tp_native_func, tp_bound_method; Type tp_function, tp_native_func, tp_bound_method;
Type tp_slice, tp_range, tp_module; Type tp_slice, tp_range, tp_module;
Type tp_super, tp_exception, tp_bytes, tp_mappingproxy; Type tp_super, tp_exception, tp_bytes, tp_mappingproxy;
Type tp_dict; Type tp_dict, tp_property;
const bool enable_os; const bool enable_os;
@ -271,11 +271,10 @@ public:
} }
PyObject* property(NativeFuncC fget, NativeFuncC fset=nullptr){ PyObject* property(NativeFuncC fget, NativeFuncC fset=nullptr){
PyObject* p = builtins->attr("property");
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(p, _0, _1); return call(_t(tp_property), _0, _1);
} }
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){
@ -640,6 +639,7 @@ DEF_NATIVE_2(Exception, tp_exception)
DEF_NATIVE_2(Bytes, tp_bytes) DEF_NATIVE_2(Bytes, tp_bytes)
DEF_NATIVE_2(MappingProxy, tp_mappingproxy) DEF_NATIVE_2(MappingProxy, tp_mappingproxy)
DEF_NATIVE_2(Dict, tp_dict) DEF_NATIVE_2(Dict, tp_dict)
DEF_NATIVE_2(Property, tp_property)
#undef DEF_NATIVE_2 #undef DEF_NATIVE_2
@ -1069,6 +1069,7 @@ inline void VM::init_builtin_types(){
tp_bytes = _new_type_object("bytes"); tp_bytes = _new_type_object("bytes");
tp_mappingproxy = _new_type_object("mappingproxy"); tp_mappingproxy = _new_type_object("mappingproxy");
tp_dict = _new_type_object("dict"); tp_dict = _new_type_object("dict");
tp_property = _new_type_object("property");
this->None = heap._new<Dummy>(_new_type_object("NoneType"), {}); this->None = heap._new<Dummy>(_new_type_object("NoneType"), {});
this->Ellipsis = heap._new<Dummy>(_new_type_object("ellipsis"), {}); this->Ellipsis = heap._new<Dummy>(_new_type_object("ellipsis"), {});
@ -1090,6 +1091,7 @@ inline void VM::init_builtin_types(){
builtins->attr().set("range", _t(tp_range)); builtins->attr().set("range", _t(tp_range));
builtins->attr().set("bytes", _t(tp_bytes)); builtins->attr().set("bytes", _t(tp_bytes));
builtins->attr().set("dict", _t(tp_dict)); builtins->attr().set("dict", _t(tp_dict));
builtins->attr().set("property", _t(tp_property));
builtins->attr().set("StopIteration", StopIteration); builtins->attr().set("StopIteration", StopIteration);
builtins->attr().set("slice", _t(tp_slice)); builtins->attr().set("slice", _t(tp_slice));
@ -1274,9 +1276,6 @@ inline PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){
return nullptr; return nullptr;
} }
DEF_SNAME(__get__);
DEF_SNAME(__set__);
// https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance // https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance
inline PyObject* VM::getattr(PyObject* obj, StrName name, bool throw_err){ inline PyObject* VM::getattr(PyObject* obj, StrName name, bool throw_err){
PyObject* objtype = _t(obj); PyObject* objtype = _t(obj);
@ -1289,8 +1288,10 @@ inline PyObject* VM::getattr(PyObject* obj, StrName name, bool throw_err){
PyObject* cls_var = find_name_in_mro(objtype, name); PyObject* cls_var = find_name_in_mro(objtype, name);
if(cls_var != nullptr){ if(cls_var != nullptr){
// handle descriptor // handle descriptor
PyObject* descr_get = _t(cls_var)->attr().try_get(__get__); if(is_non_tagged_type(cls_var, tp_property)){
if(descr_get != nullptr) return call_method(cls_var, descr_get, obj); const Property& prop = _CAST(Property&, cls_var);
return call(prop.getter, obj);
}
} }
// handle instance __dict__ // handle instance __dict__
if(!is_tagged(obj) && obj->is_attr_valid()){ if(!is_tagged(obj) && obj->is_attr_valid()){
@ -1324,8 +1325,10 @@ inline PyObject* VM::get_unbound_method(PyObject* obj, StrName name, PyObject**
if(fallback){ if(fallback){
if(cls_var != nullptr){ if(cls_var != nullptr){
// handle descriptor // handle descriptor
PyObject* descr_get = _t(cls_var)->attr().try_get(__get__); if(is_non_tagged_type(cls_var, tp_property)){
if(descr_get != nullptr) return call_method(cls_var, descr_get, obj); const Property& prop = _CAST(Property&, cls_var);
return call(prop.getter, obj);
}
} }
// handle instance __dict__ // handle instance __dict__
if(!is_tagged(obj) && obj->is_attr_valid()){ if(!is_tagged(obj) && obj->is_attr_valid()){
@ -1355,11 +1358,10 @@ inline void VM::setattr(PyObject* obj, StrName name, PyObject* value){
PyObject* cls_var = find_name_in_mro(objtype, name); PyObject* cls_var = find_name_in_mro(objtype, name);
if(cls_var != nullptr){ if(cls_var != nullptr){
// handle descriptor // handle descriptor
PyObject* cls_var_t = _t(cls_var); if(is_non_tagged_type(cls_var, tp_property)){
if(cls_var_t->attr().contains(__get__)){ const Property& prop = _CAST(Property&, cls_var);
PyObject* descr_set = cls_var_t->attr().try_get(__set__); if(prop.setter != vm->None){
if(descr_set != nullptr){ call(prop.setter, obj, value);
call_method(cls_var, descr_set, obj, value);
}else{ }else{
TypeError(fmt("readonly attribute: ", name.escape())); TypeError(fmt("readonly attribute: ", name.escape()));
} }