diff --git a/include/pocketpy/interpreter/typeinfo.h b/include/pocketpy/interpreter/typeinfo.h index 5293f71e..5be349aa 100644 --- a/include/pocketpy/interpreter/typeinfo.h +++ b/include/pocketpy/interpreter/typeinfo.h @@ -16,9 +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); + bool (*getattribute)(py_Ref self, py_Name name) PY_RAISE PY_RETURN; + bool (*setattribute)(py_Ref self, py_Name name, py_Ref val) PY_RAISE PY_RETURN; + bool (*delattribute)(py_Ref self, py_Name name) PY_RAISE; + bool (*getunboundmethod)(py_Ref self, py_Name name) PY_RETURN; py_TValue annotations; py_Dtor dtor; // destructor for this type, NULL if no dtor diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index 92bfdeb7..9604071b 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -33,6 +33,7 @@ typedef struct py_TValue { py_Type type; bool is_ptr; int extra; + union { int64_t _i64; char _chars[16]; @@ -372,9 +373,11 @@ 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)); + bool (*getattribute)(py_Ref self, py_Name name) PY_RAISE PY_RETURN, + bool (*setattribute)(py_Ref self, py_Name name, py_Ref val) + PY_RAISE PY_RETURN, + bool (*delattribute)(py_Ref self, py_Name name) PY_RAISE, + bool (*getunboundmethod)(py_Ref self, py_Name name) PY_RETURN); /// Check if the object is an instance of the given type exactly. /// Raise `TypeError` if the check fails. diff --git a/src/interpreter/typeinfo.c b/src/interpreter/typeinfo.c index 5bfcce34..0f889fac 100644 --- a/src/interpreter/typeinfo.c +++ b/src/interpreter/typeinfo.c @@ -159,10 +159,12 @@ py_Type py_newtype(const char* name, py_Type base, const py_GlobalRef module, vo 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)) { + bool (*delattribute)(py_Ref self, py_Name name), + bool (*getunboundmethod)(py_Ref self, py_Name name)) { assert(type); py_TypeInfo* ti = pk_typeinfo(type); ti->getattribute = getattribute; ti->setattribute = setattribute; ti->delattribute = delattribute; + ti->getunboundmethod = getunboundmethod; } diff --git a/src/public/internal.c b/src/public/internal.c index 5eead8d3..d7d740af 100644 --- a/src/public/internal.c +++ b/src/public/internal.c @@ -45,17 +45,11 @@ void py_initialize() { pk_initialized = true; } -void* py_malloc(size_t size) { - return PK_MALLOC(size); -} +void* py_malloc(size_t size) { return PK_MALLOC(size); } -void* py_realloc(void* ptr, size_t size) { - return PK_REALLOC(ptr, size); -} +void* py_realloc(void* ptr, size_t size) { return PK_REALLOC(ptr, size); } -void py_free(void* ptr) { - PK_FREE(ptr); -} +void py_free(void* ptr) { PK_FREE(ptr); } py_GlobalRef py_True() { return &_True; } @@ -233,7 +227,20 @@ bool pk_loadmethod(py_StackRef self, py_Name name) { self_bak = *self; } - py_Ref cls_var = py_tpfindname(type, name); + py_TypeInfo* ti = pk_typeinfo(type); + + if(ti->getunboundmethod) { + bool ok = ti->getunboundmethod(self, name); + if(ok) { + self[0] = *py_retval(); + self[1] = self_bak; + return true; + } else { + return false; + } + } + + py_Ref cls_var = pk_tpfindname(ti, name); if(cls_var != NULL) { switch(cls_var->type) { case tp_function: @@ -248,7 +255,7 @@ bool pk_loadmethod(py_StackRef self, py_Name name) { break; case tp_classmethod: self[0] = *py_getslot(cls_var, 0); - self[1] = pk_typeinfo(type)->self; + self[1] = ti->self; break; default: c11__unreachable(); }