blueloveTH 1 год назад
Родитель
Сommit
facd1c0ce6

+ 4 - 2
include/pocketpy/interpreter/vm.h

@@ -1,5 +1,6 @@
 #pragma once
 
+#include "pocketpy/objects/codeobject.h"
 #include "pocketpy/pocketpy.h"
 #include "pocketpy/interpreter/gc.h"
 #include "pocketpy/interpreter/frame.h"
@@ -70,8 +71,6 @@ void pk_VM__dtor(pk_VM* self);
 void pk_VM__push_frame(pk_VM* self, Frame* frame);
 void pk_VM__pop_frame(pk_VM* self);
 
-void pk_VM__init_builtins(pk_VM* self);
-
 typedef enum pk_FrameResult {
     RES_RETURN,
     RES_CALL,
@@ -89,7 +88,10 @@ py_Type pk_VM__new_type(pk_VM* self,
 
 pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bool opcall);
 
+const char* pk_opname(Opcode op);
+
 // type registration
+void pk_number__register();
 py_Type pk_str__register();
 py_Type pk_bytes__register();
 py_Type pk_list__register();

+ 1 - 1
include/pocketpy/pocketpy.h

@@ -117,7 +117,7 @@ bool py_issubclass(py_Type derived, py_Type base);
 /************* References *************/
 #define py_offset(p, i) (py_Ref)((char*)p + ((i) << 4))
 
-#define TypeError(x) false
+#define TypeError(...) false
 #define py_arg(i) py_offset(argv, i)
 #define py_checkargc(n)                                                                            \
     if(argc != n) return TypeError()

+ 5 - 1
src/interpreter/ceval.c

@@ -89,6 +89,9 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
     __NEXT_STEP:
         byte = *frame->ip;
 
+        // log
+        printf("byte.op: %s, line: %d\n", pk_opname(byte.op), Frame__lineno(frame));
+
         switch((Opcode)byte.op) {
             case OP_NO_OP: DISPATCH();
             /*****************************************/
@@ -614,6 +617,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
             case OP_CALL: {
                 pk_ManagedHeap__collect_if_needed(&self->heap);
                 vectorcall_opcall(byte.arg & 0xFF, byte.arg >> 8);
+                DISPATCH();
             }
             case OP_CALL_VARGS: {
                 assert(false);
@@ -667,7 +671,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
     __ERROR:
         // 1. Exception can be handled inside the current frame
         // 2. Exception need to be propagated to the upper frame
-        printf("byte.op: %d, line: %d\n", byte.op, Frame__lineno(frame));
+        printf("error.op: %s, line: %d\n", pk_opname(byte.op), Frame__lineno(frame));
         assert(false);
         return RES_ERROR;
     }

+ 1 - 1
src/interpreter/py_number.c

@@ -342,7 +342,7 @@ static bool _py_float__new__(int argc, py_Ref argv) {
     return true;
 }
 
-void pk_VM__init_builtins(pk_VM* self) {
+void pk_number__register() {
     /****** tp_int & tp_float ******/
     py_bindmagic(tp_int, __add__, _py_int__add__);
     py_bindmagic(tp_float, __add__, _py_float__add__);

+ 54 - 48
src/interpreter/vm.c

@@ -41,6 +41,7 @@ void pk_TypeInfo__ctor(pk_TypeInfo* self,
     // create type object with __dict__
     pk_ManagedHeap* heap = &pk_current_vm->heap;
     PyObject* typeobj = pk_ManagedHeap__new(heap, tp_type, -1, sizeof(py_Type));
+    *(py_Type*)PyObject__userdata(typeobj) = index;
     self->self = (py_TValue){
         .type = typeobj->type,
         .is_ptr = true,
@@ -55,6 +56,13 @@ void pk_TypeInfo__ctor(pk_TypeInfo* self,
 
 void pk_TypeInfo__dtor(pk_TypeInfo* self) { c11_vector__dtor(&self->annotated_fields); }
 
+static bool _py_object__new__(int argc, py_Ref argv) {
+    assert(argc >= 1);
+    py_Type cls = argv[0].type;
+    py_newobject(py_retval(), cls, 0, 0);
+    return true;
+}
+
 void pk_VM__ctor(pk_VM* self) {
     self->top_frame = NULL;
 
@@ -158,7 +166,10 @@ void pk_VM__ctor(pk_VM* self) {
     py_setdict(&self->builtins, py_name("NotImplemented"), &tmp);
 
     /* Do Buildin Bindings*/
-    pk_VM__init_builtins(self);
+    pk_number__register();
+    // object.__new__
+    py_bindmagic(tp_object, __new__, _py_object__new__);
+
     self->main = *py_newmodule("__main__", NULL);
 }
 
@@ -208,7 +219,7 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t ARGC, uint16_t KWARGC, bo
     // handle boundmethod, do a patch
     if(p0->type == tp_bound_method) {
         assert(false);
-        assert(py_isnull(p0+1));   // self must be NULL
+        assert(py_isnull(p0 + 1));  // self must be NULL
         // BoundMethod& bm = PK_OBJ_GET(BoundMethod, callable);
         // callable = bm.func;  // get unbound method
         // callable_t = _tp(callable);
@@ -218,7 +229,7 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t ARGC, uint16_t KWARGC, bo
     }
 
     // PyVar* _base = args.begin();
-    py_Ref argv = py_isnull(p0+1) ? p0+2 : p0+1;
+    py_Ref argv = py_isnull(p0 + 1) ? p0 + 2 : p0 + 1;
 
 #if 0
     if(callable_t == tp_function) {
@@ -301,7 +312,8 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t ARGC, uint16_t KWARGC, bo
         //     if(f.argc != -1) {
         //         if(KWARGC != 0)
         //             TypeError(
-        //                 "old-style native_func does not accept keyword arguments. If you want to skip this check, specify `argc` to -1");
+        //                 "old-style native_func does not accept keyword arguments. If you want to
+        //                 skip this check, specify `argc` to -1");
         //         if(args.size() != f.argc) {
         //             vm->TypeError(_S("expected ", f.argc, " arguments, got ", args.size()));
         //         }
@@ -314,58 +326,52 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t ARGC, uint16_t KWARGC, bo
         return RES_RETURN;
     }
 
-#if 0
     if(p0->type == tp_type) {
-        // [type, NULL, args..., kwargs...]
-        PyVar new_f = *find_name_in_mro(PK_OBJ_GET(Type, callable), __new__);
-        PyVar obj;
-        assert(new_f && (!p0[1]));
-        if(PyVar__IS_OP(&new_f, &__cached_object_new)) {
-            // fast path for object.__new__
-            obj = vm->new_object<DummyInstance>(PK_OBJ_GET(Type, callable));
-        } else {
-            PUSH(new_f);
-            PUSH(PY_NULL);
-            PUSH(callable);  // cls
-            for(PyVar o: args)
-                PUSH(o);
-            for(PyVar o: kwargs)
-                PUSH(o);
-            // if obj is not an instance of `cls`, the behavior is undefined
-            obj = vectorcall(ARGC + 1, KWARGC);
-        }
-
-        // __init__
-        PyVar self;
-        callable = get_unbound_method(obj, __init__, &self, false);
-        if(callable) {
-            callable_t = _tp(callable);
-            // replace `NULL` with `self`
-            p1[-(ARGC + 2)] = callable;
-            p1[-(ARGC + 1)] = self;
-            // [init_f, self, args..., kwargs...]
-            vectorcall(ARGC, KWARGC);
-            // We just discard the return value of `__init__`
-            // in cpython it raises a TypeError if the return value is not None
+        // [cls, NULL, args..., kwargs...]
+        py_Ref new_f = py_tpfindmagic(py_totype(p0), __new__);
+        assert(new_f && py_isnull(p0 + 1));
+
+        // prepare a copy of args and kwargs
+        int span = self->stack.sp - argv;
+        *self->stack.sp++ = *new_f;  // push __new__
+        *self->stack.sp++ = *p0;     // push cls
+        memcpy(self->stack.sp, argv, span * sizeof(py_TValue));
+        self->stack.sp += span;
+
+        // [new_f, cls, args..., kwargs...]
+        pk_FrameResult res = pk_VM__vectorcall(self, ARGC, KWARGC, false);
+        if(res == RES_ERROR) return RES_ERROR;
+        assert(res == RES_RETURN);
+        // by recursively using vectorcall, args and kwargs are consumed
+        // [cls, NULL, args..., kwargs...]
+
+        // try __init__
+        // NOTE: previous we use `get_unbound_method` but here we just use `tpfindmagic`
+        py_Ref init_f = py_tpfindmagic(py_totype(p0), __init__);
+        if(init_f) {
+            // do an inplace patch
+            *p0 = *init_f;              // __init__
+            p0[1] = self->last_retval;  // self
+            // [__init__, self, args..., kwargs...]
+            pk_FrameResult res = pk_VM__vectorcall(self, ARGC, KWARGC, false);
+            if(res == RES_ERROR) return RES_ERROR;
+            assert(res == RES_RETURN);
         } else {
             // manually reset the stack
-            s_data.reset(p0);
+            self->stack.sp = p0;
         }
-        return obj;
+        return RES_RETURN;
     }
 
     // handle `__call__` overload
-    PyVar self;
-    PyVar call_f = get_unbound_method(callable, __call__, &self, false);
-    if(self) {
-        p1[-(ARGC + 2)] = call_f;
-        p1[-(ARGC + 1)] = self;
-        // [call_f, self, args..., kwargs...]
-        return vectorcall(ARGC, KWARGC, op_call);
+    if(py_getunboundmethod(p0, __call__, false, p0, p0 + 1)) {
+        // [__call__, self, args..., kwargs...]
+        pk_FrameResult res = pk_VM__vectorcall(self, ARGC, KWARGC, false);
+        if(res == RES_ERROR) return RES_ERROR;
+        assert(res == RES_RETURN);
     }
-    TypeError(_type_name(vm, callable_t).escape() + " object is not callable");
-#endif
-    
+
+    TypeError("'%t' object is not callable", p0->type);
     PK_UNREACHABLE();
 }
 

+ 9 - 4
src/public/vm.c

@@ -1,3 +1,4 @@
+#include "pocketpy/objects/codeobject.h"
 #include "pocketpy/objects/sourcedata.h"
 #include "pocketpy/pocketpy.h"
 
@@ -25,13 +26,16 @@ void py_finalize() {
     pk_MemoryPools__finalize();
 }
 
-static void disassemble(CodeObject* co) {
+const char* pk_opname(Opcode op){
     const static char* OP_NAMES[] = {
 #define OPCODE(name) #name,
 #include "pocketpy/xmacros/opcodes.h"
 #undef OPCODE
     };
+    return OP_NAMES[op];
+}
 
+static void disassemble(CodeObject* co) {
     c11_vector /*T=int*/ jumpTargets;
     c11_vector__ctor(&jumpTargets, sizeof(int));
     for(int i = 0; i < co->codes.count; i++) {
@@ -71,9 +75,9 @@ static void disassemble(CodeObject* co) {
         snprintf(buf, sizeof(buf), "%-8s%-3s%-3d ", line, pointer, i);
         c11_sbuf__write_cstr(&ss, buf);
 
-        c11_sbuf__write_cstr(&ss, OP_NAMES[byte.op]);
+        c11_sbuf__write_cstr(&ss, pk_opname(byte.op));
         c11_sbuf__write_char(&ss, ex.is_virtual ? '*' : ' ');
-        int padding = 24 - strlen(OP_NAMES[byte.op]);
+        int padding = 24 - strlen(pk_opname(byte.op));
         for(int j = 0; j < padding; j++)
             c11_sbuf__write_char(&ss, ' ');
 
@@ -196,7 +200,7 @@ bool py_getunboundmethod(const py_Ref self,
                          bool fallback,
                          py_Ref out,
                          py_Ref out_self) {
-    return -1;
+    return false;
 }
 
 pk_TypeInfo* pk_tpinfo(const py_Ref self) {
@@ -205,6 +209,7 @@ pk_TypeInfo* pk_tpinfo(const py_Ref self) {
 }
 
 py_Ref py_tpfindmagic(py_Type t, py_Name name) {
+    assert(t);
     assert(py_ismagicname(name));
     pk_TypeInfo* types = (pk_TypeInfo*)pk_current_vm->types.data;
     do {

+ 104 - 0
tests/00_tmp.py

@@ -0,0 +1,104 @@
+# test int literals
+assert 0xffff == 65535
+assert 0xAAFFFF == 11206655
+assert 0x7fffffff == 2147483647
+assert -0xffff == -65535
+assert -0xAAFFFF == -11206655
+assert -0x7fffffff == -2147483647
+# test 64-bit
+assert 2**60-1 + 546 - 0xfffffffffffff == 1148417904979477026
+
+# test oct literals
+assert 0o1234 == 668
+assert 0o17777777777 == 2147483647
+assert -0o1234 == -668
+assert -0o17777777777 == -2147483647
+
+# test binary literals
+assert 0b10010 == 18
+assert -0b10010 == -18
+assert 0b11111111111111111111111111111111 == 4294967295
+assert -0b11111 == -31
+
+# test == != >= <= < >
+assert -1 == -1
+assert -1 != 1
+assert -1 >= -1
+assert -1 <= -1
+assert -1 < 1
+assert -1 > -2
+
+# test + - * % ** //
+assert -1 + 1 == 0
+assert -1 - 1 == -2
+assert 4 * -1 == -4
+assert 5 % 2 == 1
+assert 2 ** 3 == 8
+assert 4 // 2 == 2
+assert 5 // 2 == 2
+
+# test += -= *= //=
+x = 3
+x += 1
+assert x == 4
+x -= 1
+assert x == 3
+x *= 2
+assert x == 6
+x //= 2
+assert x == 3
+
+# test bit_length
+assert (1).bit_length() == 1
+assert (2).bit_length() == 2
+assert (3).bit_length() == 2
+
+assert (-1).bit_length() == 1
+assert (-2).bit_length() == 2
+assert (-3).bit_length() == 2
+
+assert (123123123123123).bit_length() == 47
+assert (-3123123123).bit_length() == 32
+
+# test int()
+assert int() == 0
+assert int(True) == 1
+assert int(False) == 0
+
+assert int(1) == 1
+assert int(1.0) == 1
+assert int(1.1) == 1
+assert int(1.9) == 1
+assert int(-1.9) == -1
+assert int(1.5) == 1
+assert int(-1.5) == -1
+assert int("123") == 123
+
+assert int("0x123", 16) == 291
+assert int("0o123", 8) == 83
+assert int("-0x123", 16) == -291
+assert int("-0o123", 8) == -83
+assert int("-123") == -123
+assert int("+123") == 123
+
+# test >> << & | ^
+assert 12 >> 1 == 6
+assert 12 << 1 == 24
+assert 12 & 1 == 0
+assert 12 | 1 == 13
+assert 12 ^ 1 == 13
+
+# test high precision int pow
+assert 7**21 == 558545864083284007
+assert 2**60 == 1152921504606846976
+assert -2**60 == -1152921504606846976
+assert 4**13 == 67108864
+assert (-4)**13 == -67108864
+
+assert ~3 == -4
+assert ~-3 == 2
+assert ~0 == -1
+
+# test __str__, __repr__
+assert str(1) == '1'
+assert repr(1) == '1'

+ 4 - 4
tests/01_int.py

@@ -48,10 +48,6 @@ assert x == 6
 x //= 2
 assert x == 3
 
-# test __str__, __repr__
-assert str(1) == '1'
-assert repr(1) == '1'
-
 # test bit_length
 assert (1).bit_length() == 1
 assert (2).bit_length() == 2
@@ -103,6 +99,10 @@ assert ~3 == -4
 assert ~-3 == 2
 assert ~0 == -1
 
+# test __str__, __repr__
+assert str(1) == '1'
+assert repr(1) == '1'
+
 try:
     1 // 0
     exit(1)