blueloveTH 1 рік тому
батько
коміт
35f973059c

+ 2 - 1
include/pocketpy/interpreter/modules.h

@@ -14,4 +14,5 @@ void pk__add_module_enum();
 void pk__add_module_linalg();
 void pk__add_module_array2d();
 
-void pk__add_module_conio();
+void pk__add_module_conio();
+void pk__add_module_pkpy();

+ 7 - 0
include/typings/pkpy.pyi

@@ -0,0 +1,7 @@
+from typing import Self
+
+class TValue[T]:
+    def __new__(cls, value: T) -> Self: ...
+    
+    @property
+    def value(self) -> T: ...

+ 1 - 0
src/interpreter/vm.c

@@ -217,6 +217,7 @@ void VM__ctor(VM* self) {
     pk__add_module_enum();
 
     pk__add_module_conio();
+    pk__add_module_pkpy();
 
     // add python builtins
     do {

+ 69 - 0
src/modules/pkpy.c

@@ -0,0 +1,69 @@
+#include "pocketpy/pocketpy.h"
+
+#include "pocketpy/common/utils.h"
+#include "pocketpy/objects/object.h"
+#include "pocketpy/common/sstream.h"
+#include "pocketpy/interpreter/vm.h"
+
+#define DEF_TVALUE_METHODS(T, Field)                                                               \
+    static bool TValue_##T##__new__(int argc, py_Ref argv) {                                       \
+        PY_CHECK_ARGC(2);                                                                          \
+        PY_CHECK_ARG_TYPE(0, tp_type);                                                             \
+        PY_CHECK_ARG_TYPE(1, tp_##T);                                                              \
+        *py_retval() = (py_TValue){                                                                \
+            .type = py_totype(&argv[0]),                                                           \
+            .is_ptr = false,                                                                       \
+            .Field = py_to##T(&argv[1]),                                                           \
+        };                                                                                         \
+        return true;                                                                               \
+    }                                                                                              \
+    static bool TValue_##T##_value(int argc, py_Ref argv) {                                        \
+        PY_CHECK_ARGC(1);                                                                          \
+        py_new##T(py_retval(), argv->Field);                                                       \
+        return true;                                                                               \
+    }                                                                                              \
+    static bool TValue_##T##__repr__(int argc, py_Ref argv) {                                      \
+        PY_CHECK_ARGC(1);                                                                          \
+        py_newstr(py_retval(), "<TValue_" #T " object>");                                          \
+        return true;                                                                               \
+    }
+
+DEF_TVALUE_METHODS(int, _i64)
+DEF_TVALUE_METHODS(float, _f64)
+DEF_TVALUE_METHODS(vec2, _vec2)
+DEF_TVALUE_METHODS(vec2i, _vec2i)
+
+void pk__add_module_pkpy() {
+    py_Ref mod = py_newmodule("pkpy");
+
+    py_Type ttype;
+    py_Ref TValue_dict = py_pushtmp();
+    py_newdict(TValue_dict);
+
+    ttype = pk_newtype("TValue_int", tp_object, mod, NULL, false, false);
+    py_bindmagic(ttype, __new__, TValue_int__new__);
+    py_bindmagic(ttype, __repr__, TValue_int__repr__);
+    py_bindproperty(ttype, "value", TValue_int_value, NULL);
+    py_dict_setitem(TValue_dict, py_tpobject(tp_int), py_tpobject(ttype));
+
+    ttype = pk_newtype("TValue_float", tp_object, mod, NULL, false, false);
+    py_bindmagic(ttype, __new__, TValue_float__new__);
+    py_bindmagic(ttype, __repr__, TValue_float__repr__);
+    py_bindproperty(ttype, "value", TValue_float_value, NULL);
+    py_dict_setitem(TValue_dict, py_tpobject(tp_float), py_tpobject(ttype));
+
+    ttype = pk_newtype("TValue_vec2", tp_object, mod, NULL, false, false);
+    py_bindmagic(ttype, __new__, TValue_vec2__new__);
+    py_bindmagic(ttype, __repr__, TValue_vec2__repr__);
+    py_bindproperty(ttype, "value", TValue_vec2_value, NULL);
+    py_dict_setitem(TValue_dict, py_tpobject(tp_vec2), py_tpobject(ttype));
+
+    ttype = pk_newtype("TValue_vec2i", tp_object, mod, NULL, false, false);
+    py_bindmagic(ttype, __new__, TValue_vec2i__new__);
+    py_bindmagic(ttype, __repr__, TValue_vec2i__repr__);
+    py_bindproperty(ttype, "value", TValue_vec2i_value, NULL);
+    py_dict_setitem(TValue_dict, py_tpobject(tp_vec2i), py_tpobject(ttype));
+
+    py_setdict(mod, py_name("TValue"), TValue_dict);
+    py_pop();
+}

+ 20 - 12
src/public/internal.c

@@ -12,7 +12,7 @@ static VM* pk_all_vm[16];
 static py_TValue _True, _False, _None, _NIL;
 
 void py_initialize() {
-    if(pk_current_vm){
+    if(pk_current_vm) {
         // c11__abort("py_initialize() can only be called once!");
         return;
     }
@@ -31,8 +31,11 @@ void py_initialize() {
 }
 
 py_GlobalRef py_True() { return &_True; }
+
 py_GlobalRef py_False() { return &_False; }
+
 py_GlobalRef py_None() { return &_None; }
+
 py_GlobalRef py_NIL() { return &_NIL; }
 
 void py_finalize() {
@@ -59,7 +62,7 @@ void py_switchvm(int index) {
         pk_current_vm = pk_all_vm[index] = malloc(sizeof(VM));
         memset(pk_current_vm, 0, sizeof(VM));
         VM__ctor(pk_all_vm[index]);
-    }else{
+    } else {
         pk_current_vm = pk_all_vm[index];
     }
 }
@@ -78,13 +81,9 @@ int py_currentvm() {
     return -1;
 }
 
-void* py_getvmctx(){
-    return pk_current_vm->ctx;
-}
+void* py_getvmctx() { return pk_current_vm->ctx; }
 
-void py_setvmctx(void* ctx){
-    pk_current_vm->ctx = ctx;
-}
+void py_setvmctx(void* ctx) { pk_current_vm->ctx = ctx; }
 
 void py_sys_setargv(int argc, char** argv) {
     py_GlobalRef sys = py_getmodule("sys");
@@ -161,11 +160,21 @@ bool py_pushmethod(py_Name name) {
 
 bool pk_loadmethod(py_StackRef self, py_Name name) {
     // NOTE: `out` and `out_self` may overlap with `self`
+    py_Type type;
 
-    if(name == __new__ && py_istype(self, tp_type)) {
+    if(name == __new__) {
         // __new__ acts like a @staticmethod
-        // T.__new__(...)
-        py_Ref cls_var = py_tpfindmagic(py_totype(self), name);
+        if(py_istype(self, tp_type)) {
+            // T.__new__(...)
+            type = py_totype(self);
+        } else if(py_istype(self, tp_super)) {
+            // super().__new__(...)
+            type = *(py_Type*)py_touserdata(self);
+        } else {
+            // invalid usage of `__new__`
+            return false;
+        }
+        py_Ref cls_var = py_tpfindmagic(type, name);
         if(cls_var) {
             self[0] = *cls_var;
             self[1] = *py_NIL();
@@ -174,7 +183,6 @@ bool pk_loadmethod(py_StackRef self, py_Name name) {
         return false;
     }
 
-    py_Type type;
     // handle super() proxy
     if(py_istype(self, tp_super)) {
         type = *(py_Type*)py_touserdata(self);

+ 10 - 10
src/public/py_ops.c

@@ -87,11 +87,11 @@ 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_Type type = self->type;
-    // handle super() proxy
-    if(py_istype(self, tp_super)) {
-        self = py_getslot(self, 0);
-        type = *(py_Type*)py_touserdata(self);
-    }
+    // handle super() proxy (disabled)
+    // if(py_istype(self, tp_super)) {
+    //     self = py_getslot(self, 0);
+    //     type = *(py_Type*)py_touserdata(self);
+    // }
 
     py_Ref cls_var = py_tpfindname(type, name);
     if(cls_var) {
@@ -183,11 +183,11 @@ 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;
-    // handle super() proxy
-    if(py_istype(self, tp_super)) {
-        self = py_getslot(self, 0);
-        type = *(py_Type*)py_touserdata(self);
-    }
+    // handle super() proxy (disabled)
+    // if(py_istype(self, tp_super)) {
+    //     self = py_getslot(self, 0);
+    //     type = *(py_Type*)py_touserdata(self);
+    // }
 
     py_Ref cls_var = py_tpfindname(type, name);
     if(cls_var) {

+ 16 - 2
tests/99_extras.py

@@ -6,7 +6,7 @@ except ValueError:
     pass
 
 # test some python magics
-class A:
+class TestMagics:
     def __init__(self):
         self.d = {}
 
@@ -22,7 +22,7 @@ class A:
     def __delitem__(self, index):
         del self.d[index]
 
-a = A()
+a = TestMagics()
 a['1'] = 3
 assert '1' in a
 assert '2' not in a
@@ -72,7 +72,21 @@ assert int(Number()) == 2
 assert round(Number()) == tuple()
 assert round(Number(), 1) == (1,)
 
+class Z:
+    def __new__(cls, x):
+        return cls, x
+
+class B(Z):
+    def __new__(cls, x):
+        return super().__new__(cls, x)
 
+assert Z(1) == (Z, 1)
+assert B(1) == (B, 1)
 
+from pkpy import TValue
 
+class fixed(TValue[int]):
+    def __new__(cls, value: str):
+        return super().__new__(cls, int(value))
     
+assert fixed('123').value == 123