diff --git a/include/pocketpy/interpreter/typeinfo.h b/include/pocketpy/interpreter/typeinfo.h index 5dbdcb97..5293f71e 100644 --- a/include/pocketpy/interpreter/typeinfo.h +++ b/include/pocketpy/interpreter/typeinfo.h @@ -16,6 +16,10 @@ typedef struct py_TypeInfo { bool is_python; // is it a python class? (not derived from c object) bool is_sealed; // can it be subclassed? + bool (*getattribute)(py_Ref self, py_Name name); + bool (*setattribute)(py_Ref self, py_Name name, py_Ref val); + bool (*delattribute)(py_Ref self, py_Name name); + py_TValue annotations; py_Dtor dtor; // destructor for this type, NULL if no dtor void (*on_end_subclass)(struct py_TypeInfo*); // backdoor for enum module diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index 94a0c587..6ca2c4a7 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -30,7 +30,10 @@ typedef void (*py_Dtor)(void*); #ifdef PK_IS_PUBLIC_INCLUDE typedef struct py_TValue { - int64_t _[2]; + py_Type type; + bool is_ptr; + int extra; + int64_t _i64; } py_TValue; #endif @@ -355,6 +358,12 @@ PK_API const char* py_tpname(py_Type type); /// Call a type to create a new instance. PK_API bool py_tpcall(py_Type type, int argc, py_Ref argv) PY_RAISE PY_RETURN; +/// Set attribute hooks for the given type. +PK_API void py_tphookattributes(py_Type type, + bool (*getattribute)(py_Ref self, py_Name name), + bool (*setattribute)(py_Ref self, py_Name name, py_Ref val), + bool (*delattribute)(py_Ref self, py_Name name)); + /// Check if the object is an instance of the given type exactly. /// Raise `TypeError` if the check fails. PK_API bool py_checktype(py_Ref self, py_Type type) PY_RAISE; @@ -760,11 +769,11 @@ enum py_PredefinedType { tp_bool, tp_str, tp_str_iterator, - tp_list, // c11_vector - tp_tuple, // N slots + tp_list, // c11_vector + tp_tuple, // N slots tp_list_iterator, // 1 slot tp_tuple_iterator, // 1 slot - tp_slice, // 3 slots (start, stop, step) + tp_slice, // 3 slots (start, stop, step) tp_range, tp_range_iterator, tp_module, diff --git a/src/interpreter/typeinfo.c b/src/interpreter/typeinfo.c index 9248ed4c..5bfcce34 100644 --- a/src/interpreter/typeinfo.c +++ b/src/interpreter/typeinfo.c @@ -81,6 +81,10 @@ static void py_TypeInfo__common_init(py_Name name, self->is_python = is_python; self->is_sealed = is_sealed; + self->getattribute = NULL; + self->setattribute = NULL; + self->delattribute = NULL; + self->annotations = *py_NIL(); self->dtor = dtor; self->on_end_subclass = NULL; @@ -150,4 +154,15 @@ py_Type py_newtype(const char* name, py_Type base, const py_GlobalRef module, vo py_Type type = pk_newtype(name, base, module, dtor, false, false); if(module) py_setdict(module, py_name(name), py_tpobject(type)); return type; -} \ No newline at end of file +} + +void py_tphookattributes(py_Type type, + bool (*getattribute)(py_Ref self, py_Name name), + bool (*setattribute)(py_Ref self, py_Name name, py_Ref val), + bool (*delattribute)(py_Ref self, py_Name name)) { + assert(type); + py_TypeInfo* ti = pk_typeinfo(type); + ti->getattribute = getattribute; + ti->setattribute = setattribute; + ti->delattribute = delattribute; +} diff --git a/src/public/py_ops.c b/src/public/py_ops.c index fe52b7bc..8a3fcaf5 100644 --- a/src/public/py_ops.c +++ b/src/public/py_ops.c @@ -122,6 +122,8 @@ int py_next(py_Ref val) { bool py_getattr(py_Ref self, py_Name name) { // https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance py_TypeInfo* ti = pk_typeinfo(self->type); + if(ti->getattribute) return ti->getattribute(self, name); + py_Ref cls_var = pk_tpfindname(ti, name); if(cls_var) { // handle descriptor @@ -212,8 +214,10 @@ bool py_getattr(py_Ref self, py_Name name) { } bool py_setattr(py_Ref self, py_Name name, py_Ref val) { - py_Type type = self->type; - py_Ref cls_var = py_tpfindname(type, name); + py_TypeInfo* ti = pk_typeinfo(self->type); + if(ti->setattribute) return ti->setattribute(self, name, val); + + py_Ref cls_var = pk_tpfindname(ti, name); if(cls_var) { // handle descriptor if(py_istype(cls_var, tp_property)) { @@ -239,6 +243,9 @@ bool py_setattr(py_Ref self, py_Name name, py_Ref val) { } bool py_delattr(py_Ref self, py_Name name) { + py_TypeInfo* ti = pk_typeinfo(self->type); + if(ti->delattribute) return ti->delattribute(self, name); + if(self->is_ptr && self->_obj->slots == -1) { if(py_deldict(self, name)) return true; return AttributeError(self, name);