mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
reimpl property
This commit is contained in:
parent
2e5c2b7147
commit
e1eed59030
@ -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__ + "'>"
|
||||||
|
@ -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;
|
||||||
|
@ -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]));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
32
src/vm.h
32
src/vm.h
@ -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()));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user