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

+ 11 - 5
include/pocketpy/pocketpy.h

@@ -489,12 +489,18 @@ void py_list_append(py_Ref self, py_Ref val);
 void py_list_clear(py_Ref self);
 void py_list_insert(py_Ref self, int i, py_Ref val);
 
-py_TmpRef py_dict_getitem(py_Ref self, py_Ref key) PY_RAISE;
-void py_dict_setitem(py_Ref self, py_Ref key, py_Ref val) PY_RAISE;
-void py_dict_delitem(py_Ref self, py_Ref key) PY_RAISE;
-bool py_dict_contains(py_Ref self, py_Ref key) PY_RAISE;
-int py_dict_len(py_Ref self);
+/// -1: error, 0: not found, 1: found
+int py_dict_getitem(py_Ref self, py_Ref key) PY_RAISE;
+/// true: success, false: error
+bool py_dict_setitem(py_Ref self, py_Ref key, py_Ref val) PY_RAISE;
+/// -1: error, 0: not found, 1: found (and deleted)
+int py_dict_delitem(py_Ref self, py_Ref key) PY_RAISE;
+/// -1: error, 0: not found, 1: found
+int py_dict_contains(py_Ref self, py_Ref key) PY_RAISE;
+/// true: success, false: error
 bool py_dict_apply(py_Ref self, bool (*f)(py_Ref key, py_Ref val, void* ctx), void* ctx) PY_RAISE;
+/// noexcept
+int py_dict_len(py_Ref self);
 
 /************* Others *************/
 

+ 7 - 11
src/interpreter/ceval.c

@@ -87,14 +87,9 @@ FrameResult VM__run_top_frame(VM* self) {
     __NEXT_STEP:
         byte = *frame->ip;
 
+#if PK_DEBUG
         pk_print_stack(self, frame, byte);
-
-        // #if PK_DEBUG
-        //         if(py_checkexc()) {
-        //             py_printexc();
-        //             c11__abort("unhandled exception!");
-        //         }
-        // #endif
+#endif
 
         switch((Opcode)byte.op) {
             case OP_NO_OP: DISPATCH();
@@ -506,8 +501,8 @@ FrameResult VM__run_top_frame(VM* self) {
                 py_Ref tmp = py_pushtmp();
                 py_newdict(tmp);
                 for(int i = 0; i < byte.arg * 2; i += 2) {
-                    py_dict_setitem(tmp, begin + i, begin + i + 1);
-                    if(py_checkexc()) goto __ERROR;
+                    bool ok = py_dict_setitem(tmp, begin + i, begin + i + 1);
+                    if(!ok) goto __ERROR;
                 }
                 SP() = begin;
                 PUSH(tmp);
@@ -760,8 +755,8 @@ FrameResult VM__run_top_frame(VM* self) {
             }
             case OP_DICT_ADD: {
                 // [dict, iter, key, value]
-                py_dict_setitem(FOURTH(), SECOND(), TOP());
-                if(py_checkexc()) goto __ERROR;
+                bool ok = py_dict_setitem(FOURTH(), SECOND(), TOP());
+                if(!ok) goto __ERROR;
                 STACK_SHRINK(2);
                 DISPATCH();
             }
@@ -917,6 +912,7 @@ FrameResult VM__run_top_frame(VM* self) {
             }
             case OP_END_CLASS: {
                 // [cls or decorated]
+                // TODO: if __eq__ is defined, check __ne__ and provide a default implementation
                 py_Name name = byte.arg;
                 // set into f_globals
                 py_setdict(frame->module, name, TOP());

+ 2 - 2
src/interpreter/vm.c

@@ -389,9 +389,9 @@ static bool
                 py_Ref tmp = py_pushtmp();
                 c11_sv key_sv = py_name2sv(key);
                 py_newstrn(tmp, key_sv.data, key_sv.size);
-                py_dict_setitem(&buffer[decl->starred_kwarg], tmp, &p1[2 * j + 1]);
+                bool ok = py_dict_setitem(&buffer[decl->starred_kwarg], tmp, &p1[2 * j + 1]);
                 py_pop();
-                if(py_checkexc()) return false;
+                if(!ok) return false;
             }
         }
     }

+ 1 - 0
src/public/internal.c

@@ -104,6 +104,7 @@ bool py_callcfunc(py_CFunction f, int argc, py_Ref argv) {
         c11__abort(
             "py_CFunction returns nothing! Did you forget to call `py_newnone(py_retval())`?");
     }
+    // if(py_checkexc()) { c11__abort("py_CFunction returns `true` but an exception is set!"); }
     return true;
 }
 #endif

+ 2 - 5
src/public/modules.c

@@ -617,11 +617,8 @@ static bool function__closure__getter(int argc, py_Ref argv) {
     c11__foreach(NameDict_KV, ud->closure, it) {
         // printf("%s -> %s\n", py_name2str(it->key), py_tpname(it->value.type));
         py_newstr(r0, py_name2str(it->key));
-        py_dict_setitem(retval, r0, &it->value);
-        if(py_checkexc()) {
-            py_shrink(2);
-            return false;
-        }
+        bool ok = py_dict_setitem(retval, r0, &it->value);
+        if(!ok) return false;
     }
     py_assign(py_retval(), retval);
     py_shrink(2);

+ 31 - 24
src/public/py_dict.c

@@ -164,12 +164,10 @@ static bool Dict__set(Dict* self, py_TValue* key, py_TValue* val) {
 }
 
 /// Delete an entry from the dict.
-/// If the key is found, `py_retval()` is set to the value.
-/// If the key is not found, `py_retval()` is set to `nil`.
-/// Returns false on error.
-static bool Dict__pop(Dict* self, py_Ref key) {
+/// -1: error, 0: not found, 1: found and deleted
+static int Dict__pop(Dict* self, py_Ref key) {
     py_i64 hash;
-    if(!py_hash(key, &hash)) return false;
+    if(!py_hash(key, &hash)) return -1;
     int idx = hash & (self->capacity - 1);
     for(int i = 0; i < PK_DICT_MAX_COLLISION; i++) {
         int idx2 = self->indices[idx]._[i];
@@ -182,12 +180,11 @@ static bool Dict__pop(Dict* self, py_Ref key) {
             self->indices[idx]._[i] = -1;
             self->length--;
             if(self->length < self->entries.count / 2) Dict__compact_entries(self);
-            return true;
+            return 1;
         }
-        if(res == -1) return false;  // error
+        if(res == -1) return -1;  // error
     }
-    py_newnil(py_retval());
-    return true;
+    return 0;
 }
 
 static void DictIterator__ctor(DictIterator* self, Dict* dict) {
@@ -262,8 +259,13 @@ static bool dict__setitem__(int argc, py_Ref argv) {
 static bool dict__delitem__(int argc, py_Ref argv) {
     PY_CHECK_ARGC(2);
     Dict* self = py_touserdata(argv);
-    if(!Dict__pop(self, py_arg(1))) return false;
-    return true;
+    int res = Dict__pop(self, py_arg(1));
+    if(res == 1) {
+        py_newnone(py_retval());
+        return true;
+    }
+    if(res == 0) return KeyError(py_arg(1));
+    return false;
 }
 
 static bool dict__contains__(int argc, py_Ref argv) {
@@ -396,10 +398,11 @@ static bool dict_get(int argc, py_Ref argv) {
 
 static bool dict_pop(int argc, py_Ref argv) {
     Dict* self = py_touserdata(argv);
-    if(argc < 2 || argc > 3) return TypeError("pop() takes 2 or 3 arguments (%d given)", argc);
+    if(argc < 2 || argc > 3) return TypeError("pop() takes 1 or 2 arguments (%d given)", argc - 1);
     py_Ref default_val = argc == 3 ? py_arg(2) : py_None;
-    if(!Dict__pop(self, py_arg(1))) return false;
-    if(py_isnil(py_retval())) *py_retval() = *default_val;
+    int res = Dict__pop(self, py_arg(1));
+    if(res == -1) return false;
+    if(res == 0) { py_assign(py_retval(), default_val); }
     return true;
 }
 
@@ -506,33 +509,37 @@ py_Type pk_dict_items__register() {
 
 //////////////////////////
 
-py_Ref py_dict_getitem(py_Ref self, py_Ref key) {
+int py_dict_getitem(py_Ref self, py_Ref key) {
     assert(py_isdict(self));
     Dict* ud = py_touserdata(self);
     DictEntry* entry;
-    if(!Dict__try_get(ud, key, &entry)) return NULL;
-    if(entry) return &entry->val;
-    return NULL;
+    if(!Dict__try_get(ud, key, &entry)) return -1;
+    if(entry) {
+        py_assign(py_retval(), &entry->val);
+        return 1;
+    }
+    return 0;
 }
 
-void py_dict_delitem(py_Ref self, py_Ref key) {
+int py_dict_delitem(py_Ref self, py_Ref key) {
     assert(py_isdict(self));
     Dict* ud = py_touserdata(self);
-    Dict__pop(ud, key);
+    return Dict__pop(ud, key);
 }
 
-void py_dict_setitem(py_Ref self, py_Ref key, py_Ref val) {
+bool py_dict_setitem(py_Ref self, py_Ref key, py_Ref val) {
     assert(py_isdict(self));
     Dict* ud = py_touserdata(self);
-    Dict__set(ud, key, val);
+    return Dict__set(ud, key, val);
 }
 
-bool py_dict_contains(py_Ref self, py_Ref key) {
+int py_dict_contains(py_Ref self, py_Ref key) {
     assert(py_isdict(self));
     Dict* ud = py_touserdata(self);
     DictEntry* entry;
     bool ok = Dict__try_get(ud, key, &entry);
-    return ok && entry != NULL;
+    if(!ok) return -1;
+    return entry ? 1 : 0;
 }
 
 int py_dict_len(py_Ref self) {

+ 1 - 1
src/public/py_exception.c

@@ -66,7 +66,7 @@ static bool _py_BaseException__init__(int argc, py_Ref argv) {
         py_setslot(py_arg(0), 0, py_arg(1));
         return true;
     }
-    return TypeError("__init__() takes at most 2 arguments but %d were given", argc);
+    return TypeError("__init__() takes at most 1 arguments but %d were given", argc - 1);
 }
 
 static bool _py_BaseException__repr__(int argc, py_Ref argv) {