diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index 167aa9d6..92f47cec 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -136,5 +136,4 @@ py_Type pk_code__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 +void pk_mappingproxy__namedict(py_Ref out, py_Ref object); \ No newline at end of file diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index e9ad94ad..eef52054 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -208,38 +208,31 @@ FrameResult VM__run_top_frame(VM* self) { DISPATCH(); } case OP_LOAD_NAME: { - // assert(frame->is_dynamic); py_Name name = byte.arg; - py_TValue* tmp; - py_assign(SP()++, py_name2ref(name)); // locals - if(!py_isnone(&frame->p0[1])) { - 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; - } - } + int res = Frame__getlocal(frame, name); + if(res == 1) { + PUSH(&self->last_retval); + DISPATCH(); + } + if(res == -1) goto __ERROR; + // closure + py_Ref tmp = Frame__getclosure(frame, name); + if(tmp != NULL) { + PUSH(tmp); + DISPATCH(); } // globals - if(py_getitem(&frame->p0[0], TOP())) { - py_assign(TOP(), py_retval()); + res = Frame__getglobal(frame, name); + if(res == 1) { + PUSH(&self->last_retval); DISPATCH(); - } else { - if(py_matchexc(tp_KeyError)) { - py_clearexc(NULL); - } else { - goto __ERROR; - } } + if(res == -1) goto __ERROR; // builtins tmp = py_getdict(&self->builtins, name); if(tmp != NULL) { - py_assign(TOP(), tmp); + PUSH(tmp); DISPATCH(); } NameError(name); @@ -353,36 +346,22 @@ FrameResult VM__run_top_frame(VM* self) { DISPATCH(); } case OP_STORE_NAME: { - // assert(frame->is_dynamic); py_Name name = byte.arg; - py_assign(SP()++, py_name2ref(name)); - // [value, name] - if(!py_isnone(&frame->p0[1])) { + if(frame->locals != NULL) { // locals - if(py_setitem(&frame->p0[1], TOP(), SECOND())) { - STACK_SHRINK(2); + int res = Frame__setlocal(frame, name, TOP()); + if(res == 1) { + POP(); DISPATCH(); - } else { - if(py_matchexc(tp_KeyError)) { - py_clearexc(NULL); - NameError(name); - } - goto __ERROR; } + if(res == 0) 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; - } + if(!Frame__setglobal(frame, name, TOP())) { goto __ERROR; } + POP(); + DISPATCH(); } - DISPATCH(); } case OP_STORE_GLOBAL: { if(!Frame__setglobal(frame, byte.arg, TOP())) goto __ERROR; @@ -424,42 +403,27 @@ FrameResult VM__run_top_frame(VM* self) { DISPATCH(); } case OP_DELETE_NAME: { - // assert(frame->is_dynamic); py_Name name = byte.arg; - py_assign(SP()++, py_name2ref(name)); - if(!py_isnone(&frame->p0[1])) { + if(frame->locals != NULL) { // locals - if(py_delitem(&frame->p0[1], TOP())) { - POP(); - DISPATCH(); - } else { - if(py_matchexc(tp_KeyError)) { - py_clearexc(NULL); - NameError(name); - } - goto __ERROR; - } + int res = Frame__dellocal(frame, name); + if(res == 1) DISPATCH(); + if(res == 0) NameError(name); + goto __ERROR; } else { // globals - if(py_delitem(&frame->p0[0], TOP())) { - POP(); - DISPATCH(); - } else { - if(py_matchexc(tp_KeyError)) { - py_clearexc(NULL); - NameError(name); - } - goto __ERROR; - } + int res = Frame__delglobal(frame, name); + if(res == 1) DISPATCH(); + if(res == 0) NameError(name); + goto __ERROR; + DISPATCH(); } - DISPATCH(); } case OP_DELETE_GLOBAL: { py_Name name = byte.arg; int res = Frame__delglobal(frame, name); if(res == 1) DISPATCH(); if(res == -1) goto __ERROR; - // res == 0 NameError(name); goto __ERROR; } diff --git a/src/interpreter/frame.c b/src/interpreter/frame.c index dddc8236..77e9456d 100644 --- a/src/interpreter/frame.c +++ b/src/interpreter/frame.c @@ -54,7 +54,9 @@ Frame* Frame__new(const CodeObject* co, py_Ref locals, bool is_p0_function, bool is_locals_proxy) { - assert(module->type == tp_module || module->type == tp_dict); + assert(module->type == tp_module); + assert(globals->type == tp_module || globals->type == tp_dict); + assert(locals->type == tp_locals || locals->type == tp_dict || locals->type == tp_nil); Frame* self = FixedMemoryPool__alloc(&pk_current_vm->pool_frame); self->f_back = NULL; self->co = co; @@ -78,10 +80,8 @@ void Frame__delete(Frame* self) { FixedMemoryPool__dealloc(&pk_current_vm->pool_frame, self); } -py_StackRef Frame__locals_sp(Frame *self){ - if(!self->is_locals_proxy){ - return self->locals; - } +py_StackRef Frame__locals_sp(Frame* self) { + if(!self->is_locals_proxy) { return self->locals; } return self->p0; } diff --git a/src/public/exec.c b/src/public/exec.c index 94cc7f5b..86bd3867 100644 --- a/src/public/exec.c +++ b/src/public/exec.c @@ -3,15 +3,13 @@ #include "pocketpy/pocketpy.h" #include "pocketpy/common/utils.h" -#include "pocketpy/common/sstream.h" -#include "pocketpy/objects/object.h" #include "pocketpy/interpreter/vm.h" #include "pocketpy/compiler/compiler.h" #include py_Type pk_code__register() { py_Type type = pk_newtype("code", tp_object, NULL, (py_Dtor)CodeObject__dtor, false, true); - pk__tp_set_marker(type, (void (*)(void *))CodeObject__gc_mark); + pk__tp_set_marker(type, (void (*)(void*))CodeObject__gc_mark); return type; } @@ -56,7 +54,7 @@ bool pk_exec(CodeObject* co, py_Ref module) { assert(module->type == tp_module); py_StackRef sp = vm->stack.sp; - Frame* frame = Frame__new(co, sp, module, module, sp, false, false); + Frame* frame = Frame__new(co, sp, module, module, py_NIL(), false, false); VM__push_frame(vm, frame); FrameResult res = VM__run_top_frame(vm); if(res == RES_ERROR) return false; @@ -70,7 +68,7 @@ bool pk_execdyn(CodeObject* co, py_Ref module, py_Ref globals, py_Ref locals) { assert(module->type == tp_module); py_StackRef sp = vm->stack.sp; - assert(globals != NULL && locals != NULL); + assert(globals != NULL); if(globals->type == tp_namedict) { globals = py_getslot(globals, 0); diff --git a/src/public/modules.c b/src/public/modules.c index 450ec2e2..762292a7 100644 --- a/src/public/modules.c +++ b/src/public/modules.c @@ -507,7 +507,7 @@ void py_newglobals(py_Ref out) { void py_newlocals(py_Ref out) { Frame* frame = pk_current_vm->top_frame; - if(!frame || !frame->is_p0_function) { + if(!frame) { py_newglobals(out); return; } @@ -524,61 +524,97 @@ void py_newlocals(py_Ref out) { py_assign(out, py_retval()); } +static void pk_push_locals_proxy() { + Frame* frame = pk_current_vm->top_frame; + if(!frame) { + py_pushnil(); + return; + } + if(frame->is_locals_proxy) { + py_push(frame->locals); + } else { + if(py_isnil(frame->locals)) { + py_pushnil(); + } else { + py_StackRef out = py_pushtmp(); + out->type = tp_locals; + out->is_ptr = false; + out->extra = 0; + // this is a weak reference + // which will expire when the frame is destroyed + out->_ptr = frame; + } + } +} + static bool _builtins_execdyn(const char* title, int argc, py_Ref argv, enum py_CompileMode mode) { switch(argc) { case 1: { py_newglobals(py_pushtmp()); - py_newlocals(py_pushtmp()); + pk_push_locals_proxy(); break; } case 2: { + // globals if(py_isnone(py_arg(1))) { py_newglobals(py_pushtmp()); } else { if(!py_checktype(py_arg(1), tp_dict)) return false; py_push(py_arg(1)); } - py_pushnone(); + // locals + pk_push_locals_proxy(); break; } case 3: { + // globals if(py_isnone(py_arg(1))) { py_newglobals(py_pushtmp()); } else { if(!py_checktype(py_arg(1), tp_dict)) return false; py_push(py_arg(1)); } - py_push(py_arg(2)); + // locals + if(py_isnone(py_arg(2))) { + pk_push_locals_proxy(); + } else { + if(!py_checktype(py_arg(2), tp_dict)) return false; + py_push(py_arg(2)); + } break; } default: return TypeError("%s() takes at most 3 arguments", title); } - py_Ref code; + py_Ref tmp_code; if(py_isstr(argv)) { bool ok = py_compile(py_tostr(argv), "", mode, true); if(!ok) return false; - code = py_retval(); + tmp_code = py_retval(); } else if(py_istype(argv, tp_code)) { - code = argv; + tmp_code = argv; } else { return TypeError("%s() expected 'str' or 'code', got '%t'", title, argv->type); } - py_push(code); // keep it alive + py_push(tmp_code); // keep it alive + Frame* frame = pk_current_vm->top_frame; // [globals, locals, code] - CodeObject* co = py_touserdata(code); - if(!co->src->is_dynamic) { + CodeObject* code = py_touserdata(tmp_code); + if(code->src->is_dynamic) { + bool ok = pk_execdyn(code, frame ? frame->module : NULL, py_peek(-3), py_peek(-2)); py_shrink(3); - if(argc != 1) - return ValueError("code object is not dynamic, `globals` and `locals` must be None"); + return ok; + } else { + if(argc != 1) { + return ValueError( + "code object is not dynamic, `globals` and `locals` must not be specified"); + } + bool ok = pk_exec(code, frame ? frame->module : NULL); + py_shrink(3); + return ok; } - - Frame* frame = pk_current_vm->top_frame; - bool ok = pk_execdyn(co, frame ? frame->module : NULL, py_peek(-3), py_peek(-2)); - py_shrink(3); - return ok; } static bool builtins_exec(int argc, py_Ref argv) { diff --git a/src/public/py_mappingproxy.c b/src/public/py_mappingproxy.c index 174c6d81..525016c0 100644 --- a/src/public/py_mappingproxy.c +++ b/src/public/py_mappingproxy.c @@ -1,9 +1,7 @@ #include "pocketpy/pocketpy.h" -#include "pocketpy/common/utils.h" #include "pocketpy/objects/object.h" #include "pocketpy/interpreter/vm.h" -#include "pocketpy/common/sstream.h" #include void pk_mappingproxy__namedict(py_Ref out, py_Ref object) { @@ -104,15 +102,3 @@ py_Type pk_namedict__register() { py_bindmethod(type, "clear", namedict_clear); return type; } - -////////////////////// - -void pk_mappingproxy__locals(py_Ref out, Frame* frame) { - assert(frame->is_p0_function && !frame->is_locals_proxy); - out->type = tp_locals; - out->is_ptr = false; - out->extra = 0; - // this is a weak reference - // locals() will expire when the frame is destroyed - out->_ptr = frame; -}