blueloveTH 1 gadu atpakaļ
vecāks
revīzija
a87641c04d

+ 3 - 0
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();
 

+ 1 - 0
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*);

+ 14 - 29
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, <self>, 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;
 

+ 62 - 0
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;
+}

+ 10 - 2
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);
 }

+ 19 - 6
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;

+ 26 - 0
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;
+}

+ 6 - 0
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);