blueloveTH 1 tahun lalu
induk
melakukan
4829568c87

+ 6 - 0
include/pocketpy/common/config.h

@@ -50,3 +50,9 @@
 #else
     #define PK_PLATFORM_SEP '/'
 #endif
+
+#ifdef NDEBUG
+    #define PK_DEBUG 0
+#else
+    #define PK_DEBUG 1
+#endif

+ 9 - 1
include/pocketpy/pocketpy.h

@@ -304,7 +304,7 @@ bool py_setitem(py_Ref self, py_Ref key, py_Ref val) PY_RAISE;
 /// Python equivalent to `del self[key]`.
 bool py_delitem(py_Ref self, py_Ref key) PY_RAISE;
 
-/// Perform a binary operation on the stack.
+/// Perform a binary operation.
 /// The result will be set to `py_retval()`.
 /// The stack remains unchanged after the operation.
 bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop) PY_RAISE;
@@ -431,6 +431,14 @@ bool py_isidentical(py_Ref, py_Ref);
 /// The stack remains unchanged after the operation.
 bool py_call(py_Ref f, int argc, py_Ref argv) PY_RAISE;
 
+#if PK_DEBUG
+/// Call a py_CFunction in a safe way.
+/// This function does extra checks to help you debug `py_CFunction`.
+bool py_callcfunc(py_CFunction f, int argc, py_Ref argv) PY_RAISE;
+#else
+#define py_callcfunc(f, argc, argv) f(argc, argv)
+#endif
+
 /// Python equivalent to `str(val)`.
 bool py_str(py_Ref val) PY_RAISE;
 /// Python equivalent to `repr(val)`.

+ 4 - 4
src/interpreter/ceval.c

@@ -269,7 +269,7 @@ FrameResult VM__run_top_frame(VM* self) {
                 py_Ref magic = py_tpfindmagic(SECOND()->type, __getitem__);
                 if(magic) {
                     if(magic->type == tp_nativefunc) {
-                        if(!magic->_cfunc(2, SECOND())) goto __ERROR;
+                        if(!py_callcfunc(magic->_cfunc, 2, SECOND())) goto __ERROR;
                         POP();
                     } else {
                         INSERT_THIRD();     // [?, a, b]
@@ -322,7 +322,7 @@ FrameResult VM__run_top_frame(VM* self) {
                 if(magic) {
                     PUSH(THIRD());  // [val, a, b, val]
                     if(magic->type == tp_nativefunc) {
-                        if(!magic->_cfunc(3, THIRD())) goto __ERROR;
+                        if(!py_callcfunc(magic->_cfunc, 3, THIRD())) goto __ERROR;
                         STACK_SHRINK(4);
                     } else {
                         *FOURTH() = *magic;  // [__selitem__, a, b, val]
@@ -389,7 +389,7 @@ FrameResult VM__run_top_frame(VM* self) {
                 py_Ref magic = py_tpfindmagic(SECOND()->type, __delitem__);
                 if(magic) {
                     if(magic->type == tp_nativefunc) {
-                        if(!magic->_cfunc(2, SECOND())) goto __ERROR;
+                        if(!py_callcfunc(magic->_cfunc, 2, SECOND())) goto __ERROR;
                         STACK_SHRINK(2);
                     } else {
                         INSERT_THIRD();     // [?, a, b]
@@ -533,7 +533,7 @@ FrameResult VM__run_top_frame(VM* self) {
                 py_Ref magic = py_tpfindmagic(SECOND()->type, __contains__);
                 if(magic) {
                     if(magic->type == tp_nativefunc) {
-                        if(!magic->_cfunc(2, SECOND())) goto __ERROR;
+                        if(!py_callcfunc(magic->_cfunc, 2, SECOND())) goto __ERROR;
                         STACK_SHRINK(2);
                     } else {
                         INSERT_THIRD();     // [?, b, a]

+ 2 - 2
src/interpreter/vm.c

@@ -477,7 +477,7 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
     }
 
     if(p0->type == tp_nativefunc) {
-        bool ok = p0->_cfunc(p1 - argv, argv);
+        bool ok = py_callcfunc(p0->_cfunc, p1 - argv, argv);
         self->stack.sp = p0;
         return ok ? RES_RETURN : RES_ERROR;
     }
@@ -657,6 +657,6 @@ bool pk_wrapper__self(int argc, py_Ref argv) {
     return true;
 }
 
-bool pk_wrapper__NotImplementedError(int argc, py_Ref argv){
+bool pk_wrapper__NotImplementedError(int argc, py_Ref argv) {
     return py_exception(tp_NotImplementedError, "");
 }

+ 1 - 0
src/modules/os.c

@@ -32,6 +32,7 @@ static bool os_chdir(int argc, py_Ref argv) {
     const char* path = py_tostr(py_arg(0));
     int code = platform_chdir(path);
     if(code != 0) return py_exception(tp_OSError, "chdir() failed: %d", code);
+    py_newnone(py_retval());
     return true;
 }
 

+ 11 - 1
src/public/internal.c

@@ -105,7 +105,7 @@ bool py_exec(const char* source, const char* filename, enum py_CompileMode mode,
 
 bool py_call(py_Ref f, int argc, py_Ref argv) {
     if(f->type == tp_nativefunc) {
-        return f->_cfunc(argc, argv);
+        return py_callcfunc(f->_cfunc, argc, argv);
     } else {
         py_push(f);
         py_pushnil();
@@ -115,6 +115,16 @@ bool py_call(py_Ref f, int argc, py_Ref argv) {
     }
 }
 
+bool py_callcfunc(py_CFunction f, int argc, py_Ref argv) {
+    py_StackRef p0 = py_peek(0);
+    py_newnil(py_retval());
+    bool ok = f(argc, argv);
+    if(!ok) return false;
+    if(py_peek(0) != p0) c11__abort("py_CFunction must not change the stack!");
+    if(py_isnil(py_retval())) c11__abort("py_CFunction must set the return value!");
+    return true;
+}
+
 bool py_vectorcall(uint16_t argc, uint16_t kwargc) {
     VM* vm = pk_current_vm;
     return VM__vectorcall(vm, argc, kwargc, false) != RES_ERROR;

+ 2 - 0
src/public/modules.c

@@ -319,6 +319,7 @@ static bool builtins_setattr(int argc, py_Ref argv) {
     PY_CHECK_ARGC(3);
     PY_CHECK_ARG_TYPE(1, tp_str);
     py_Name name = py_namev(py_tosv(py_arg(1)));
+    py_newnone(py_retval());
     return py_setattr(py_arg(0), name, py_arg(2));
 }
 
@@ -344,6 +345,7 @@ static bool builtins_delattr(int argc, py_Ref argv) {
     PY_CHECK_ARGC(2);
     PY_CHECK_ARG_TYPE(1, tp_str);
     py_Name name = py_namev(py_tosv(py_arg(1)));
+    py_newnone(py_retval());
     return py_delattr(py_arg(0), name);
 }
 

+ 4 - 0
src/public/py_dict.c

@@ -211,6 +211,7 @@ static bool dict__new__(int argc, py_Ref argv) {
 }
 
 static bool dict__init__(int argc, py_Ref argv) {
+    py_newnone(py_retval());
     if(argc > 2) return TypeError("dict.__init__() takes at most 2 arguments (%d given)", argc);
     if(argc == 1) return true;
     assert(argc == 2);
@@ -324,6 +325,7 @@ static bool dict__eq__(int argc, py_Ref argv) {
             return true;
         }
     }
+    py_newbool(py_retval(), true);
     return true;
 }
 
@@ -340,6 +342,7 @@ static bool dict_clear(int argc, py_Ref argv) {
     PY_CHECK_ARGC(1);
     Dict* self = py_touserdata(argv);
     Dict__clear(self);
+    py_newnone(py_retval());
     return true;
 }
 
@@ -366,6 +369,7 @@ static bool dict_update(int argc, py_Ref argv) {
         if(py_isnil(&entry->key)) continue;
         if(!Dict__set(self, &entry->key, &entry->val)) return false;
     }
+    py_newnone(py_retval());
     return true;
 }
 

+ 7 - 4
src/public/py_exception.c

@@ -60,7 +60,8 @@ static bool _py_BaseException__new__(int argc, py_Ref argv) {
 }
 
 static bool _py_BaseException__init__(int argc, py_Ref argv) {
-    if(argc == 1 + 0) { return true; }
+    py_newnone(py_retval());
+    if(argc == 1 + 0) return true;
     if(argc == 1 + 1) {
         py_setslot(py_arg(0), 0, py_arg(1));
         return true;
@@ -138,7 +139,7 @@ void py_printexc() {
     free(msg);
 }
 
-static void c11_sbuf__write_exc(c11_sbuf* self, py_Ref exc){
+static void c11_sbuf__write_exc(c11_sbuf* self, py_Ref exc) {
     if(true) { c11_sbuf__write_cstr(self, "Traceback (most recent call last):\n"); }
 
     BaseException* ud = py_touserdata(exc);
@@ -174,7 +175,9 @@ char* py_formatexc() {
         c11_sbuf__write_exc(&ss, &vm->curr_exception);
     } else {
         c11_sbuf__write_exc(&ss, inner);
-        c11_sbuf__write_cstr(&ss, "\n\nDuring handling of the above exception, another exception occurred:\n\n");
+        c11_sbuf__write_cstr(
+            &ss,
+            "\n\nDuring handling of the above exception, another exception occurred:\n\n");
         c11_sbuf__write_exc(&ss, &vm->curr_exception);
     }
 
@@ -207,7 +210,7 @@ bool py_exception(py_Type type, const char* fmt, ...) {
 bool py_raise(py_Ref exc) {
     assert(py_isinstance(exc, tp_BaseException));
     VM* vm = pk_current_vm;
-    if(!py_isnil(&vm->curr_exception)){
+    if(!py_isnil(&vm->curr_exception)) {
         // inner exception
         py_setslot(exc, 1, &vm->curr_exception);
     }

+ 1 - 0
src/public/py_list.c

@@ -167,6 +167,7 @@ static bool list__setitem__(int argc, py_Ref argv) {
     int index = py_toint(py_arg(1));
     if(!pk__normalize_index(&index, self->count)) return false;
     c11__setitem(py_TValue, self, index, *py_arg(2));
+    py_newnone(py_retval());
     return true;
 }
 

+ 1 - 1
src/public/values.c

@@ -101,7 +101,7 @@ py_Name
     return py_name(ud->decl->code.name->data);
 }
 
-void py_newboundmethod(py_Ref out, py_Ref self, py_Ref func){
+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);