diff --git a/include/pocketpy/interpreter/frame.h b/include/pocketpy/interpreter/frame.h index 2c7e1f68..2fc72534 100644 --- a/include/pocketpy/interpreter/frame.h +++ b/include/pocketpy/interpreter/frame.h @@ -36,17 +36,19 @@ typedef struct Frame { const Bytecode* ip; const CodeObject* co; py_GlobalRef module; - bool has_function; // is p0 a function? - py_StackRef p0; // unwinding base - py_StackRef locals; // locals base + py_StackRef p0; // unwinding base + py_StackRef locals; // locals base + bool has_function; // is p0 a function? + bool is_dynamic; // is dynamic frame? UnwindTarget* uw_list; } Frame; Frame* Frame__new(const CodeObject* co, py_GlobalRef module, - bool has_function, py_StackRef p0, - py_StackRef locals); + py_StackRef locals, + bool has_function, + bool is_dynamic); void Frame__delete(Frame* self); int Frame__ip(const Frame* self); diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index b90a6b7a..03057501 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -125,5 +125,11 @@ py_Type pk_property__register(); py_Type pk_staticmethod__register(); py_Type pk_classmethod__register(); py_Type pk_generator__register(); +py_Type pk_namedict__register(); +py_Type pk_locals__register(); py_TValue pk_builtins__register(); + +/* mappingproxy */ +void pk_mappingproxy__namedict(py_Ref out, py_Ref object); +void pk_mappingproxy__locals(py_Ref out, Frame* frame); \ No newline at end of file diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index 099910af..739b476c 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -79,7 +79,7 @@ bool py_exec(const char* source, /// Assume `globals()` and `locals()` are pushed to the stack. /// After the execution, the result will be set to `py_retval()`. /// The stack size will be reduced by 2. -bool py_execdynamic(const char* source, +bool py_execdyn(const char* source, const char* filename, enum py_CompileMode mode, py_Ref module) PY_RAISE; @@ -526,7 +526,8 @@ enum py_PredefinedTypes { tp_BaseException, // 2 slots (arg + inner exc) tp_Exception, tp_bytes, - tp_mappingproxy, + tp_namedict, + tp_locals, tp_dict, tp_dict_items, // 1 slot tp_property, // 2 slots (getter + setter) diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index 4b51d69f..5835616a 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -159,28 +159,65 @@ FrameResult VM__run_top_frame(VM* self) { } case OP_LOAD_NAME: { py_Name name = byte.arg; - py_Ref tmp = Frame__f_locals_try_get(frame, name); - if(tmp != NULL) { - if(py_isnil(tmp)) { - UnboundLocalError(name); - goto __ERROR; + py_TValue* tmp; + if(!frame->is_dynamic) { + // locals + tmp = Frame__f_locals_try_get(frame, name); + if(tmp != NULL) { + if(py_isnil(tmp)) { + UnboundLocalError(name); + goto __ERROR; + } + PUSH(tmp); + DISPATCH(); + } + // closure + tmp = Frame__f_closure_try_get(frame, name); + if(tmp != NULL) { + PUSH(tmp); + DISPATCH(); + } + // globals + tmp = py_getdict(frame->module, name); + if(tmp != NULL) { + PUSH(tmp); + DISPATCH(); + } + } else { + py_newstr(SP()++, py_name2str(name)); + // locals + if(py_getitem(&frame->p0[1], TOP())) { + py_assign(TOP(), py_retval()); + DISPATCH(); + } else { + if(py_matchexc(tp_KeyError)) { + py_clearexc(NULL); + } else { + goto __ERROR; + } + } + // closure + tmp = Frame__f_closure_try_get(frame, name); + if(tmp != NULL) { + py_assign(TOP(), tmp); + DISPATCH(); + } + // globals + if(py_getitem(&frame->p0[0], TOP())) { + py_assign(TOP(), py_retval()); + DISPATCH(); + } else { + if(py_matchexc(tp_KeyError)) { + py_clearexc(NULL); + } else { + goto __ERROR; + } } - PUSH(tmp); - DISPATCH(); - } - tmp = Frame__f_closure_try_get(frame, name); - if(tmp != NULL) { - PUSH(tmp); - DISPATCH(); - } - tmp = py_getdict(frame->module, name); - if(tmp != NULL) { - PUSH(tmp); - DISPATCH(); } + // builtins tmp = py_getdict(&self->builtins, name); if(tmp != NULL) { - PUSH(tmp); + py_assign(TOP(), tmp); DISPATCH(); } NameError(name); @@ -284,19 +321,35 @@ FrameResult VM__run_top_frame(VM* self) { } case OP_STORE_FAST: frame->locals[byte.arg] = POPX(); DISPATCH(); case OP_STORE_NAME: { + assert(frame->is_dynamic); py_Name name = byte.arg; - if(frame->has_function) { - py_Ref slot = Frame__f_locals_try_get(frame, name); - if(slot != NULL) { - *slot = *TOP(); // store in locals if possible + py_newstr(SP()++, py_name2str(name)); + // [value, name] + if(!py_isnone(&frame->p0[1])){ + // locals + if(py_setitem(&frame->p0[1], TOP(), SECOND())) { + STACK_SHRINK(2); + DISPATCH(); } else { - NameError(name); + if(py_matchexc(tp_KeyError)) { + py_clearexc(NULL); + NameError(name); + } + goto __ERROR; + } + }else{ + // globals + if(py_setitem(&frame->p0[0], TOP(), SECOND())) { + STACK_SHRINK(2); + DISPATCH(); + } else { + if(py_matchexc(tp_KeyError)) { + py_clearexc(NULL); + NameError(name); + } goto __ERROR; } - } else { - py_setdict(frame->module, name, TOP()); } - POP(); DISPATCH(); } case OP_STORE_GLOBAL: { @@ -339,19 +392,31 @@ FrameResult VM__run_top_frame(VM* self) { DISPATCH(); } case OP_DELETE_NAME: { + assert(frame->is_dynamic); py_Name name = byte.arg; - if(frame->has_function) { - py_TValue* slot = Frame__f_locals_try_get(frame, name); - if(slot) { - py_newnil(slot); + py_newstr(SP()++, py_name2str(name)); + if(!py_isnone(&frame->p0[1])){ + // locals + if(py_delitem(&frame->p0[1], TOP())) { + POP(); + DISPATCH(); } else { - NameError(name); + if(py_matchexc(tp_KeyError)) { + py_clearexc(NULL); + NameError(name); + } goto __ERROR; } - } else { - bool ok = py_deldict(frame->module, name); - if(!ok) { - NameError(name); + }else{ + // globals + if(py_delitem(&frame->p0[0], TOP())) { + POP(); + DISPATCH(); + } else { + if(py_matchexc(tp_KeyError)) { + py_clearexc(NULL); + NameError(name); + } goto __ERROR; } } @@ -889,8 +954,9 @@ FrameResult VM__run_top_frame(VM* self) { case OP_WITH_ENTER: { // [expr] py_push(TOP()); - if(!py_pushmethod(__enter__)){ - TypeError("'%t' object does not support the context manager protocol", TOP()->type); + if(!py_pushmethod(__enter__)) { + TypeError("'%t' object does not support the context manager protocol", + TOP()->type); goto __ERROR; } if(!py_vectorcall(0, 0)) goto __ERROR; @@ -900,8 +966,9 @@ FrameResult VM__run_top_frame(VM* self) { case OP_WITH_EXIT: { // [expr] py_push(TOP()); - if(!py_pushmethod(__exit__)){ - TypeError("'%t' object does not support the context manager protocol", TOP()->type); + if(!py_pushmethod(__exit__)) { + TypeError("'%t' object does not support the context manager protocol", + TOP()->type); goto __ERROR; } if(!py_vectorcall(0, 0)) goto __ERROR; diff --git a/src/interpreter/frame.c b/src/interpreter/frame.c index 73eab4a4..6b58a3b7 100644 --- a/src/interpreter/frame.c +++ b/src/interpreter/frame.c @@ -2,6 +2,7 @@ #include "pocketpy/objects/codeobject.h" #include "pocketpy/objects/object.h" #include "pocketpy/pocketpy.h" +#include void ValueStack__ctor(ValueStack* self) { self->sp = self->begin; @@ -37,18 +38,20 @@ void UnwindTarget__delete(UnwindTarget* self) { free(self); } Frame* Frame__new(const CodeObject* co, py_GlobalRef module, - bool has_function, py_StackRef p0, - py_StackRef locals) { + py_StackRef locals, + bool has_function, + bool is_dynamic) { static_assert(sizeof(Frame) <= kPoolFrameBlockSize, "!(sizeof(Frame) <= kPoolFrameBlockSize)"); Frame* self = PoolFrame_alloc(); self->f_back = NULL; self->ip = (Bytecode*)co->codes.data - 1; self->co = co; self->module = module; - self->has_function = has_function; self->p0 = p0; self->locals = locals; + self->has_function = has_function; + self->is_dynamic = is_dynamic; self->uw_list = NULL; return self; } @@ -150,5 +153,6 @@ int Frame__iblock(const Frame* self) { } py_TValue* Frame__f_locals_try_get(Frame* self, py_Name name) { + assert(!self->is_dynamic); return FastLocals__try_get_by_name(self->locals, self->co, name); } \ No newline at end of file diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index 92194873..bcdabc96 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -7,6 +7,7 @@ #include "pocketpy/objects/base.h" #include "pocketpy/common/_generated.h" #include "pocketpy/pocketpy.h" +#include static char* pk_default_import_file(const char* path) { #if PK_ENABLE_OS @@ -112,7 +113,8 @@ void VM__ctor(VM* self) { validate(tp_BaseException, pk_BaseException__register()); validate(tp_Exception, pk_Exception__register()); validate(tp_bytes, pk_bytes__register()); - validate(tp_mappingproxy, pk_newtype("mappingproxy", tp_object, NULL, NULL, false, true)); + validate(tp_namedict, pk_namedict__register()); + validate(tp_locals, pk_locals__register()); validate(tp_dict, pk_dict__register()); validate(tp_dict_items, pk_dict_items__register()); @@ -427,10 +429,10 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall memcpy(argv, self->__vectorcall_buffer, co->nlocals * sizeof(py_TValue)); // submit the call if(!fn->cfunc) { - VM__push_frame(self, Frame__new(co, &fn->module, true, p0, argv)); + VM__push_frame(self, Frame__new(co, &fn->module, p0, argv, true, false)); return opcall ? RES_CALL : VM__run_top_frame(self); } else { - bool ok = fn->cfunc(co->nlocals, argv); + bool ok = py_callcfunc(fn->cfunc, co->nlocals, argv); self->stack.sp = p0; return ok ? RES_RETURN : RES_ERROR; } @@ -451,22 +453,16 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall // initialize local variables to py_NIL memset(p1, 0, (char*)self->stack.sp - (char*)p1); // submit the call - VM__push_frame(self, Frame__new(co, &fn->module, true, p0, argv)); + VM__push_frame(self, Frame__new(co, &fn->module, p0, argv, true, false)); return opcall ? RES_CALL : VM__run_top_frame(self); case FuncType_GENERATOR: { bool ok = prepare_py_call(self->__vectorcall_buffer, argv, p1, kwargc, fn->decl); if(!ok) return RES_ERROR; - Frame* frame = Frame__new(co, &fn->module, false, p0, argv); + Frame* frame = Frame__new(co, &fn->module, p0, argv, false, false); pk_newgenerator(py_retval(), frame, self->__vectorcall_buffer, co->nlocals); self->stack.sp = p0; return RES_RETURN; } - // prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl); - // s_data.reset(p0); - // callstack.emplace(nullptr, co, fn._module, callable.get(), nullptr); - // return __py_generator( - // callstack.popx(), - // ArgsView(__vectorcall_buffer, __vectorcall_buffer + co->nlocals)); default: c11__unreachedable(); }; diff --git a/src/public/internal.c b/src/public/internal.c index 6131c9f5..7883b270 100644 --- a/src/public/internal.c +++ b/src/public/internal.c @@ -7,6 +7,7 @@ #include "pocketpy/objects/object.h" #include "pocketpy/interpreter/vm.h" #include "pocketpy/compiler/compiler.h" +#include #include VM* pk_current_vm; @@ -103,7 +104,7 @@ static bool _py_exec(const char* source, sp -= 2; } - Frame* frame = Frame__new(&co, module, false, sp, sp); + Frame* frame = Frame__new(&co, module, sp, sp, false, is_dynamic); VM__push_frame(vm, frame); FrameResult res = VM__run_top_frame(vm); CodeObject__dtor(&co); @@ -117,10 +118,7 @@ bool py_exec(const char* source, const char* filename, enum py_CompileMode mode, return _py_exec(source, filename, mode, module, false); } -bool py_execdynamic(const char* source, - const char* filename, - enum py_CompileMode mode, - py_Ref module) { +bool py_execdyn(const char* source, const char* filename, enum py_CompileMode mode, py_Ref module) { return _py_exec(source, filename, mode, module, true); } @@ -128,11 +126,14 @@ bool py_call(py_Ref f, int argc, py_Ref argv) { if(f->type == tp_nativefunc) { return py_callcfunc(f->_cfunc, argc, argv); } else { + py_StackRef p0 = py_peek(0); py_push(f); py_pushnil(); for(int i = 0; i < argc; i++) py_push(py_offset(argv, i)); - return py_vectorcall(argc, 0); + bool ok = py_vectorcall(argc, 0); + pk_current_vm->stack.sp = p0; + return ok; } } @@ -150,8 +151,7 @@ bool py_callcfunc(py_CFunction f, int argc, py_Ref argv) { } bool py_vectorcall(uint16_t argc, uint16_t kwargc) { - VM* vm = pk_current_vm; - return VM__vectorcall(vm, argc, kwargc, false) != RES_ERROR; + return VM__vectorcall(pk_current_vm, argc, kwargc, false) != RES_ERROR; } py_Ref py_retval() { return &pk_current_vm->last_retval; } diff --git a/src/public/modules.c b/src/public/modules.c index 1f64a109..3094b244 100644 --- a/src/public/modules.c +++ b/src/public/modules.c @@ -252,20 +252,6 @@ static bool builtins_print(int argc, py_Ref argv) { return true; } -static bool builtins_exec(int argc, py_Ref argv) { - PY_CHECK_ARGC(1); - PY_CHECK_ARG_TYPE(0, tp_str); - Frame* frame = pk_current_vm->top_frame; - return py_exec(py_tostr(argv), "", EXEC_MODE, frame->module); -} - -static bool builtins_eval(int argc, py_Ref argv) { - PY_CHECK_ARGC(1); - PY_CHECK_ARG_TYPE(0, tp_str); - Frame* frame = pk_current_vm->top_frame; - return py_exec(py_tostr(argv), "", EVAL_MODE, frame->module); -} - static bool builtins_isinstance(int argc, py_Ref argv) { PY_CHECK_ARGC(2); if(py_istuple(py_arg(1))) { @@ -301,10 +287,9 @@ static bool builtins_getattr(int argc, py_Ref argv) { if(argc == 2) { return py_getattr(py_arg(0), name); } else if(argc == 3) { - py_StackRef p0 = py_peek(0); bool ok = py_getattr(py_arg(0), name); if(!ok && py_matchexc(tp_AttributeError)) { - py_clearexc(p0); + py_clearexc(NULL); py_assign(py_retval(), py_arg(2)); return true; // default value } @@ -327,14 +312,13 @@ static bool builtins_hasattr(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_StackRef p0 = py_peek(0); bool ok = py_getattr(py_arg(0), name); if(ok) { py_newbool(py_retval(), true); return true; } if(py_matchexc(tp_AttributeError)) { - py_clearexc(p0); + py_clearexc(NULL); py_newbool(py_retval(), false); return true; } @@ -369,6 +353,64 @@ static bool builtins_ord(int argc, py_Ref argv) { return true; } +static bool builtins_globals(int argc, py_Ref argv) { + Frame* frame = pk_current_vm->top_frame; + if(frame->is_dynamic){ + py_assign(py_retval(), &frame->p0[0]); + return true; + } + pk_mappingproxy__namedict(py_retval(), frame->module); + return true; +} + +static bool builtins_locals(int argc, py_Ref argv){ + Frame* frame = pk_current_vm->top_frame; + if(frame->is_dynamic){ + py_assign(py_retval(), &frame->p0[1]); + return true; + } + if(!frame->has_function) return builtins_globals(argc, argv); + pk_mappingproxy__locals(py_retval(), frame); + return true; +} + +static bool _builtins_execdyn(const char* title, int argc, py_Ref argv, enum py_CompileMode mode) { + PY_CHECK_ARG_TYPE(0, tp_str); + Frame* frame = pk_current_vm->top_frame; + switch(argc){ + case 1: { + // system globals + system locals + if(!builtins_globals(0, NULL)) return false; + py_push(py_retval()); + if(!builtins_locals(0, NULL)) return false; + py_push(py_retval()); + break; + } + case 2: { + // user globals + user globals + py_push(py_arg(1)); + py_push(py_arg(1)); + break; + } + case 3: { + // user globals + user locals + py_push(py_arg(1)); + py_push(py_arg(2)); + break; + } + default: return TypeError("%s() takes at most 3 arguments", title); + } + return py_execdyn(py_tostr(argv), "", mode, frame->module); +} + +static bool builtins_exec(int argc, py_Ref argv){ + return _builtins_execdyn("exec", argc, argv, EXEC_MODE); +} + +static bool builtins_eval(int argc, py_Ref argv) { + return _builtins_execdyn("eval", argc, argv, EVAL_MODE); +} + static bool NoneType__repr__(int argc, py_Ref argv) { py_newstr(py_retval(), "None"); return true; @@ -396,9 +438,6 @@ py_TValue pk_builtins__register() { py_bindfunc(builtins, "abs", builtins_abs); py_bindfunc(builtins, "divmod", builtins_divmod); - py_bindfunc(builtins, "exec", builtins_exec); - py_bindfunc(builtins, "eval", builtins_eval); - py_bind(builtins, "print(*args, sep=' ', end='\\n')", builtins_print); py_bindfunc(builtins, "isinstance", builtins_isinstance); @@ -412,6 +451,11 @@ py_TValue pk_builtins__register() { py_bindfunc(builtins, "chr", builtins_chr); py_bindfunc(builtins, "ord", builtins_ord); + py_bindfunc(builtins, "globals", builtins_globals); + py_bindfunc(builtins, "locals", builtins_locals); + py_bindfunc(builtins, "exec", builtins_exec); + py_bindfunc(builtins, "eval", builtins_eval); + // some patches py_bindmagic(tp_NoneType, __repr__, NoneType__repr__); py_bindmagic(tp_ellipsis, __repr__, ellipsis__repr__); diff --git a/src/public/py_mappingproxy.c b/src/public/py_mappingproxy.c new file mode 100644 index 00000000..e4b4c646 --- /dev/null +++ b/src/public/py_mappingproxy.c @@ -0,0 +1,123 @@ +#include "pocketpy/pocketpy.h" + +#include "pocketpy/common/utils.h" +#include "pocketpy/objects/object.h" +#include "pocketpy/interpreter/vm.h" +#include "pocketpy/common/sstream.h" + + +void pk_mappingproxy__namedict(py_Ref out, py_Ref object){ + py_newobject(py_retval(), tp_namedict, 1, 0); + assert(object->is_ptr && object->_obj->slots == -1); + py_setslot(py_retval(), 0, object); +} + +static bool namedict__getitem__(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_Ref res = py_getdict(py_getslot(argv, 0), name); + if(!res) return KeyError(py_arg(1)); + py_assign(py_retval(), res); + return true; +} + +static bool namedict__setitem__(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_setdict(py_getslot(argv, 0), name, py_arg(2)); + py_newnone(py_retval()); + return true; +} + +static bool namedict__delitem__(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))); + if(!py_deldict(py_getslot(argv, 0), name)) return KeyError(py_arg(1)); + py_newnone(py_retval()); + return true; +} + +static bool namedict__contains__(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_Ref res = py_getdict(py_getslot(argv, 0), name); + py_newbool(py_retval(), res != NULL); + return true; +} + +py_Type pk_namedict__register() { + py_Type type = pk_newtype("namedict", tp_object, NULL, NULL, false, true); + + py_bindmagic(type, __getitem__, namedict__getitem__); + py_bindmagic(type, __setitem__, namedict__setitem__); + py_bindmagic(type, __delitem__, namedict__delitem__); + py_bindmagic(type, __contains__, namedict__contains__); + return type; +} + +////////////////////// + +void pk_mappingproxy__locals(py_Ref out, Frame* frame){ + assert(frame->has_function && !frame->is_dynamic); + Frame** ud = py_newobject(py_retval(), tp_locals, 0, sizeof(Frame*)); + *ud = frame; +} + +static bool locals__getitem__(int argc, py_Ref argv){ + PY_CHECK_ARGC(2); + PY_CHECK_ARG_TYPE(1, tp_str); + Frame** ud = py_touserdata(argv); + py_Name name = py_namev(py_tosv(py_arg(1))); + py_Ref slot = Frame__f_locals_try_get(*ud, name); + if(!slot || py_isnil(slot)) return KeyError(py_arg(1)); + py_assign(py_retval(), slot); + return true; +} + +static bool locals__setitem__(int argc, py_Ref argv){ + PY_CHECK_ARGC(3); + PY_CHECK_ARG_TYPE(1, tp_str); + Frame** ud = py_touserdata(argv); + py_Name name = py_namev(py_tosv(py_arg(1))); + py_Ref slot = Frame__f_locals_try_get(*ud, name); + if(!slot) return KeyError(py_arg(1)); + py_assign(slot, py_arg(2)); + py_newnone(py_retval()); + return true; +} + +static bool locals__delitem__(int argc, py_Ref argv){ + PY_CHECK_ARGC(2); + PY_CHECK_ARG_TYPE(1, tp_str); + Frame** ud = py_touserdata(argv); + py_Name name = py_namev(py_tosv(py_arg(1))); + py_Ref res = Frame__f_locals_try_get(*ud, name); + if(!res || py_isnil(res)) return KeyError(py_arg(1)); + py_newnil(res); + py_newnone(py_retval()); + return true; +} + +static bool locals__contains__(int argc, py_Ref argv){ + PY_CHECK_ARGC(2); + PY_CHECK_ARG_TYPE(1, tp_str); + Frame** ud = py_touserdata(argv); + py_Name name = py_namev(py_tosv(py_arg(1))); + py_Ref slot = Frame__f_locals_try_get(*ud, name); + py_newbool(py_retval(), slot && !py_isnil(slot)); + return true; +} + +py_Type pk_locals__register() { + py_Type type = pk_newtype("locals", tp_locals, NULL, NULL, false, true); + + py_bindmagic(type, __getitem__, locals__getitem__); + py_bindmagic(type, __setitem__, locals__setitem__); + py_bindmagic(type, __delitem__, locals__delitem__); + py_bindmagic(type, __contains__, locals__contains__); + return type; +} \ No newline at end of file diff --git a/src/public/py_object.c b/src/public/py_object.c index 1709de23..f3029c2f 100644 --- a/src/public/py_object.c +++ b/src/public/py_object.c @@ -44,6 +44,16 @@ static bool object__repr__(int argc, py_Ref argv) { return true; } +static bool object__dict__getter(int argc, py_Ref argv) { + PY_CHECK_ARGC(1); + if(argv->is_ptr && argv->_obj->slots == -1){ + pk_mappingproxy__namedict(py_retval(), argv); + }else{ + py_newnone(py_retval()); + } + return true; +} + static bool type__repr__(int argc, py_Ref argv) { PY_CHECK_ARGC(1); c11_sbuf buf; @@ -88,6 +98,7 @@ void pk_object__register() { py_bindmagic(tp_object, __eq__, object__eq__); py_bindmagic(tp_object, __ne__, object__ne__); py_bindmagic(tp_object, __repr__, object__repr__); + py_bindproperty(tp_object, "__dict__", object__dict__getter, NULL); py_bindmagic(tp_type, __repr__, type__repr__); py_bindmagic(tp_type, __new__, type__new__); diff --git a/src/public/py_ops.c b/src/public/py_ops.c index ac4bfe47..9a95747c 100644 --- a/src/public/py_ops.c +++ b/src/public/py_ops.c @@ -75,10 +75,9 @@ int py_next(py_Ref val) { TypeError("'%t' object is not an iterator", val->type); return -1; } - py_StackRef p0 = py_peek(0); if(py_call(tmp, 1, val)) return true; if(vm->curr_exception.type == tp_StopIteration) { - py_clearexc(p0); + py_clearexc(NULL); vm->is_stopiteration = true; } int retval = vm->is_stopiteration ? 0 : -1; diff --git a/tests/99_builtin_func.py b/tests/99_builtin_func.py index 5ff315f1..7f078cbe 100644 --- a/tests/99_builtin_func.py +++ b/tests/99_builtin_func.py @@ -327,8 +327,8 @@ assert s.step == 3 # test slice.__repr__ assert type(repr(slice(1,1,1))) is str -# /************ mappingproxy ************/ -# test mappingproxy.keys: +# /************ namedict ************/ +# test namedict.keys: class A(): def __init__(self): self.a = 10 @@ -336,12 +336,12 @@ class A(): pass -my_mappingproxy = A().__dict__ -assert type(my_mappingproxy.keys()) is list +my_namedict = A().__dict__ +assert type(my_namedict.keys()) is list # 未完全测试准确性----------------------------------------------- -# test mappingproxy.values: +# test namedict.values: class A(): def __init__(self): self.a = 10 @@ -349,8 +349,8 @@ class A(): pass -my_mappingproxy = A().__dict__ -assert type(my_mappingproxy.values()) is list +my_namedict = A().__dict__ +assert type(my_namedict.values()) is list class A(): @@ -360,8 +360,8 @@ class A(): pass -my_mappingproxy = A().__dict__ -assert type(len(my_mappingproxy)) is int +my_namedict = A().__dict__ +assert type(len(my_namedict)) is int class A(): @@ -371,11 +371,11 @@ class A(): pass -my_mappingproxy = A().__dict__ +my_namedict = A().__dict__ try: - hash(my_mappingproxy) - print('未能拦截错误, 在测试 mappingproxy.__hash__') + hash(my_namedict) + print('未能拦截错误, 在测试 namedict.__hash__') exit(1) except TypeError: pass @@ -393,7 +393,7 @@ except TypeError: pass # 未完全测试准确性----------------------------------------------- -# test mappingproxy.__repr__: +# test namedict.__repr__: class A(): def __init__(self): self.a = 10 @@ -401,8 +401,8 @@ class A(): pass -my_mappingproxy = A().__dict__ -assert type(repr(my_mappingproxy)) is str +my_namedict = A().__dict__ +assert type(repr(my_namedict)) is str # /************ dict ************/