From a87641c04da361691be633987c53835ea9ca5bb5 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sun, 4 Aug 2024 22:31:33 +0800 Subject: [PATCH] ... --- include/pocketpy/interpreter/vm.h | 3 ++ include/pocketpy/pocketpy.h | 1 + src/interpreter/vm.c | 43 +++++++-------------- src/public/py_method.c | 62 +++++++++++++++++++++++++++++++ src/public/py_object.c | 12 +++++- src/public/py_ops.c | 25 ++++++++++--- src/public/py_property.c | 26 +++++++++++++ src/public/values.c | 6 +++ 8 files changed, 141 insertions(+), 37 deletions(-) create mode 100644 src/public/py_method.c create mode 100644 src/public/py_property.c diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index 13e945de..12d10fba 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -123,6 +123,9 @@ py_Type pk_range_iterator__register(); py_Type pk_BaseException__register(); py_Type pk_Exception__register(); py_Type pk_super__register(); +py_Type pk_property__register(); +py_Type pk_staticmethod__register(); +py_Type pk_classmethod__register(); py_TValue pk_builtins__register(); diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index 225592b1..e1256205 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -98,6 +98,7 @@ void py_newslice(py_Ref); void py_newnativefunc(py_Ref out, py_CFunction); py_Name py_newfunction(py_Ref out, const char* sig, py_CFunction f, const char* docstring, int slots); +void py_newboundmethod(py_Ref out, py_Ref self, py_Ref func); /************* Name Convertions *************/ py_Name py_name(const char*); diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index 3aadb91d..590877a4 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -116,11 +116,11 @@ void VM__ctor(VM* self) { validate(tp_dict, pk_dict__register()); validate(tp_dict_items, pk_dict_items__register()); - validate(tp_property, pk_newtype("property", tp_object, NULL, NULL, false, true)); + validate(tp_property, pk_property__register()); validate(tp_star_wrapper, pk_newtype("star_wrapper", tp_object, NULL, NULL, false, true)); - validate(tp_staticmethod, pk_newtype("staticmethod", tp_object, NULL, NULL, false, true)); - validate(tp_classmethod, pk_newtype("classmethod", tp_object, NULL, NULL, false, true)); + validate(tp_staticmethod, pk_staticmethod__register()); + validate(tp_classmethod, pk_classmethod__register()); validate(tp_NoneType, pk_newtype("NoneType", tp_object, NULL, NULL, false, true)); validate(tp_NotImplementedType, @@ -134,24 +134,11 @@ void VM__ctor(VM* self) { self->builtins = pk_builtins__register(); /* Setup Public Builtin Types */ - py_Type public_types[] = {tp_object, - tp_type, - tp_int, - tp_float, - tp_bool, - tp_str, - tp_list, - tp_tuple, - tp_slice, - tp_range, - tp_bytes, - tp_dict, - tp_property, - tp_super, - tp_BaseException, - tp_Exception, - tp_StopIteration, - tp_SyntaxError}; + py_Type public_types[] = {tp_object, tp_type, tp_int, tp_float, + tp_bool, tp_str, tp_list, tp_tuple, + tp_slice, tp_range, tp_bytes, tp_dict, + tp_property, tp_staticmethod, tp_classmethod, tp_super, + tp_BaseException, tp_Exception, tp_StopIteration, tp_SyntaxError}; for(int i = 0; i < c11__count_array(public_types); i++) { py_Type t = public_types[i]; @@ -202,7 +189,8 @@ void VM__dtor(VM* self) { // destroy all objects ManagedHeap__dtor(&self->heap); // clear frames - while(self->top_frame) VM__pop_frame(self); + while(self->top_frame) + VM__pop_frame(self); NameDict__dtor(&self->modules); c11__foreach(py_TypeInfo, &self->types, ti) py_TypeInfo__dtor(ti); c11_vector__dtor(&self->types); @@ -218,6 +206,7 @@ void VM__pop_frame(VM* self) { assert(self->top_frame); Frame* frame = self->top_frame; // reset stack pointer + self->stack.sp = frame->p0; // pop frame and delete self->top_frame = frame->f_back; @@ -382,18 +371,14 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall // [callable, , args..., kwargs...] // ^p0 ^p1 ^_sp -#if 0 // handle boundmethod, do a patch if(p0->type == tp_boundmethod) { assert(py_isnil(p0 + 1)); // self must be NULL - // BoundMethod& bm = PK_OBJ_GET(BoundMethod, callable); - // callable = bm.func; // get unbound method - // callable_t = _tp(callable); - // p1[-(ARGC + 2)] = bm.func; - // p1[-(ARGC + 1)] = bm.self; + py_TValue* slots = PyObject__slots(p0->_obj); + p0[0] = slots[1]; // callable + p0[1] = slots[0]; // self // [unbound, self, args..., kwargs...] } -#endif py_Ref argv = py_isnil(p0 + 1) ? p0 + 2 : p0 + 1; diff --git a/src/public/py_method.c b/src/public/py_method.c new file mode 100644 index 00000000..ef3b24e5 --- /dev/null +++ b/src/public/py_method.c @@ -0,0 +1,62 @@ +#include "pocketpy/pocketpy.h" + +#include "pocketpy/common/utils.h" +#include "pocketpy/objects/object.h" +#include "pocketpy/interpreter/vm.h" + +/* staticmethod */ + +static bool staticmethod__new__(int argc, py_Ref argv) { + PY_CHECK_ARGC(2); + py_newobject(py_retval(), tp_staticmethod, 1, 0); + py_setslot(py_retval(), 0, py_arg(1)); + return true; +} + +py_Type pk_staticmethod__register(){ + py_Type type = pk_newtype("staticmethod", tp_object, NULL, NULL, false, true); + + py_bindmagic(type, __new__, staticmethod__new__); + return type; +} + +/* classmethod */ +static bool classmethod__new__(int argc, py_Ref argv) { + PY_CHECK_ARGC(2); + py_newobject(py_retval(), tp_classmethod, 1, 0); + py_setslot(py_retval(), 0, py_arg(1)); + return true; +} + +py_Type pk_classmethod__register(){ + py_Type type = pk_newtype("classmethod", tp_object, NULL, NULL, false, true); + + py_bindmagic(type, __new__, classmethod__new__); + return type; +} + +/* boundmethod */ +static bool boundmethod__new__(int argc, py_Ref argv) { + return NotImplementedError(); +} + +static bool boundmethod__self__getter(int argc, py_Ref argv) { + PY_CHECK_ARGC(1); + py_assign(py_retval(), py_getslot(argv, 0)); + return true; +} + +static bool boundmethod__func__getter(int argc, py_Ref argv) { + PY_CHECK_ARGC(1); + py_assign(py_retval(), py_getslot(argv, 1)); + return true; +} + +py_Type pk_boundmethod__register(){ + py_Type type = pk_newtype("boundmethod", tp_object, NULL, NULL, false, true); + + py_bindmagic(type, __new__, boundmethod__new__); + py_bindproperty(type, "__self__", boundmethod__self__getter, NULL); + py_bindproperty(type, "__func__", boundmethod__func__getter, NULL); + return type; +} \ No newline at end of file diff --git a/src/public/py_object.c b/src/public/py_object.c index 5d6046ec..e39015f8 100644 --- a/src/public/py_object.c +++ b/src/public/py_object.c @@ -68,8 +68,16 @@ static bool type__base__getter(int argc, py_Ref argv) { return true; } +static bool type__name__getter(int argc, py_Ref argv) { + PY_CHECK_ARGC(1); + py_Type type = py_totype(argv); + py_TypeInfo* ti = c11__at(py_TypeInfo, &pk_current_vm->types, type); + py_newstr(py_retval(), py_name2str(ti->name)); + return true; +} + void pk_object__register() { - // use staticmethod + // TODO: use staticmethod py_bindmagic(tp_object, __new__, object__new__); py_bindmagic(tp_object, __hash__, object__hash__); @@ -77,9 +85,9 @@ void pk_object__register() { py_bindmagic(tp_object, __ne__, object__ne__); py_bindmagic(tp_object, __repr__, object__repr__); - // type patch... py_bindmagic(tp_type, __repr__, type__repr__); py_bindmagic(tp_type, __new__, type__new__); py_bindproperty(tp_type, "__base__", type__base__getter, NULL); + py_bindproperty(tp_type, "__name__", type__name__getter, NULL); } \ No newline at end of file diff --git a/src/public/py_ops.c b/src/public/py_ops.c index 23ec4507..ad2e46bd 100644 --- a/src/public/py_ops.c +++ b/src/public/py_ops.c @@ -113,8 +113,9 @@ bool py_getattr(py_Ref self, py_Name name) { if(py_istype(res, tp_staticmethod)) { res = py_getslot(res, 0); } else if(py_istype(res, tp_classmethod)) { - // TODO: make a closure - assert(false); + res = py_getslot(res, 0); + py_newboundmethod(py_retval(), self, res); + return true; } py_assign(py_retval(), res); return true; @@ -125,10 +126,22 @@ bool py_getattr(py_Ref self, py_Name name) { if(cls_var) { // bound method is non-data descriptor switch(cls_var->type) { - case tp_function: assert(false); - case tp_nativefunc: assert(false); - case tp_staticmethod: assert(false); - case tp_classmethod: assert(false); + case tp_function: { + py_newboundmethod(py_retval(), self, cls_var); + return true; + } + case tp_nativefunc: { + py_newboundmethod(py_retval(), self, cls_var); + return true; + } + case tp_staticmethod: { + py_assign(py_retval(), py_getslot(cls_var, 0)); + return true; + } + case tp_classmethod: { + py_newboundmethod(py_retval(), py_tpobject(type), py_getslot(cls_var, 0)); + return true; + } default: { py_assign(py_retval(), cls_var); return true; diff --git a/src/public/py_property.c b/src/public/py_property.c new file mode 100644 index 00000000..a0a7903f --- /dev/null +++ b/src/public/py_property.c @@ -0,0 +1,26 @@ +#include "pocketpy/pocketpy.h" + +#include "pocketpy/common/utils.h" +#include "pocketpy/objects/object.h" +#include "pocketpy/interpreter/vm.h" + +static bool property__new__(int argc, py_Ref argv) { + py_newobject(py_retval(), tp_property, 2, 0); + if(argc == 1 + 1) { + py_setslot(py_retval(), 0, py_arg(1)); + py_setslot(py_retval(), 1, py_None); + } else if(argc == 1 + 2) { + py_setslot(py_retval(), 0, py_arg(1)); + py_setslot(py_retval(), 1, py_arg(2)); + } else { + return TypeError("property() expected 1 or 2 arguments, got %d", argc); + } + return true; +} + +py_Type pk_property__register() { + py_Type type = pk_newtype("property", tp_object, NULL, NULL, false, true); + + py_bindmagic(type, __new__, property__new__); + return type; +} diff --git a/src/public/values.c b/src/public/values.c index e9c88728..a5dc45f4 100644 --- a/src/public/values.c +++ b/src/public/values.c @@ -101,6 +101,12 @@ py_Name return py_name(ud->decl->code.name->data); } +void py_newboundmethod(py_Ref out, py_Ref self, py_Ref func){ + py_newobject(out, tp_boundmethod, 2, 0); + py_setslot(out, 0, self); + py_setslot(out, 1, func); +} + void* py_newobject(py_Ref out, py_Type type, int slots, int udsize) { ManagedHeap* heap = &pk_current_vm->heap; PyObject* obj = ManagedHeap__gcnew(heap, type, slots, udsize);