diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index 3f97fea8..57bee28c 100644 --- a/include/pocketpy/pocketpy.h +++ b/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 *************/ diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index abc176a4..7e9cf108 100644 --- a/src/interpreter/ceval.c +++ b/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()); diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index 31fd7dcf..9cc75821 100644 --- a/src/interpreter/vm.c +++ b/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; } } } diff --git a/src/public/internal.c b/src/public/internal.c index 9da074e3..36d40699 100644 --- a/src/public/internal.c +++ b/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 diff --git a/src/public/modules.c b/src/public/modules.c index 97e9099e..986875ce 100644 --- a/src/public/modules.c +++ b/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); diff --git a/src/public/py_dict.c b/src/public/py_dict.c index e60b6b62..6582e085 100644 --- a/src/public/py_dict.c +++ b/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) { diff --git a/src/public/py_exception.c b/src/public/py_exception.c index 8c328c43..681822ba 100644 --- a/src/public/py_exception.c +++ b/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) {