diff --git a/include/pocketpy/interpreter/frame.h b/include/pocketpy/interpreter/frame.h index 8f5d07b9..91a1f698 100644 --- a/include/pocketpy/interpreter/frame.h +++ b/include/pocketpy/interpreter/frame.h @@ -6,7 +6,7 @@ #include "pocketpy/objects/object.h" #include "pocketpy/pocketpy.h" -py_TValue* FastLocals__try_get_by_name(py_TValue* locals, const CodeObject* co, py_Name name); +void FastLocals__to_dict(py_TValue* locals, const CodeObject* co) PY_RETURN; NameDict* FastLocals__to_namedict(py_TValue* locals, const CodeObject* co); typedef struct ValueStack { @@ -17,7 +17,7 @@ typedef struct ValueStack { } ValueStack; void ValueStack__ctor(ValueStack* self); -void ValueStack__clear(ValueStack* self); +void ValueStack__dtor(ValueStack* self); typedef struct UnwindTarget { struct UnwindTarget* next; @@ -58,7 +58,7 @@ bool Frame__setglobal(Frame* self, py_Name name, py_TValue* val) PY_RAISE; int Frame__delglobal(Frame* self, py_Name name) PY_RAISE; int Frame__getlocal(Frame* self, py_Name name) PY_RAISE PY_RETURN; -int Frame__setlocal(Frame* self, py_Name name, py_TValue* val) PY_RAISE; +bool Frame__setlocal(Frame* self, py_Name name, py_TValue* val) PY_RAISE; int Frame__dellocal(Frame* self, py_Name name) PY_RAISE; py_Ref Frame__getclosure(Frame* self, py_Name name); diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index 11edd121..167aa9d6 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -131,7 +131,6 @@ 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_Type pk_code__register(); py_TValue pk_builtins__register(); diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index 4997b6da..f9bba425 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -135,7 +135,6 @@ PK_API bool py_compile(const char* source, /// Python equivalent to `globals()`. PK_API void py_newglobals(py_OutRef); /// Python equivalent to `locals()`. -/// @return a temporary object, which expires on the associated function return. PK_API void py_newlocals(py_OutRef); /************* Values Creation *************/ diff --git a/src/interpreter/frame.c b/src/interpreter/frame.c index 20f84177..73c4f675 100644 --- a/src/interpreter/frame.c +++ b/src/interpreter/frame.c @@ -11,12 +11,21 @@ void ValueStack__ctor(ValueStack* self) { self->end = self->begin + PK_VM_STACK_SIZE; } -void ValueStack__clear(ValueStack* self) { self->sp = self->begin; } +void ValueStack__dtor(ValueStack* self) { self->sp = self->begin; } -py_TValue* FastLocals__try_get_by_name(py_TValue* locals, const CodeObject* co, py_Name name) { - int index = c11_smallmap_n2i__get(&co->varnames_inv, name, -1); - if(index == -1) return NULL; - return &locals[index]; +void FastLocals__to_dict(py_TValue* locals, const CodeObject* co) { + py_StackRef dict = py_pushtmp(); + py_newdict(dict); + c11__foreach(c11_smallmap_n2i_KV, &co->varnames_inv, entry) { + py_TValue* value = &locals[entry->value]; + if(!py_isnil(value)) { + bool ok = py_dict_setitem(dict, py_name2ref(entry->key), value); + assert(ok); + (void)ok; + } + } + py_assign(py_retval(), dict); + py_pop(); } NameDict* FastLocals__to_namedict(py_TValue* locals, const CodeObject* co) { @@ -151,78 +160,62 @@ int Frame__delglobal(Frame* self, py_Name name) { int Frame__getlocal(Frame* self, py_Name name) { if(self->is_locals_proxy) { - py_StackRef p0 = py_peek(0); - py_push(self->locals); - py_pushmethod(__getitem__); - py_push(py_name2ref(name)); - bool ok = py_vectorcall(1, 0); - if(!ok) { - if(py_matchexc(tp_KeyError)) { - py_clearexc(p0); - return 0; - } - return -1; + if(self->locals->type == tp_locals) { + self = self->locals->_ptr; + } else { + assert(self->locals->type == tp_dict); + return py_dict_getitem(self->locals, py_name2ref(name)); } - return 1; - } else { - py_Ref slot = Frame__getlocal_noproxy(self, name); - if(slot == NULL) return 0; // bad slot - if(py_isnil(slot)) { - UnboundLocalError(name); - return -1; - } - py_assign(py_retval(), slot); - return 1; } + py_Ref slot = Frame__getlocal_noproxy(self, name); + if(slot == NULL) return 0; // bad slot + if(py_isnil(slot)) { + UnboundLocalError(name); + return -1; + } + py_assign(py_retval(), slot); + return 1; } -int Frame__setlocal(Frame* self, py_Name name, py_TValue* val) { +bool Frame__setlocal(Frame* self, py_Name name, py_TValue* val) { if(self->is_locals_proxy) { - py_push(self->locals); - py_pushmethod(__setitem__); - py_push(py_name2ref(name)); - py_push(val); - bool ok = py_vectorcall(2, 0); - if(!ok) return -1; - return 1; - } else { - py_Ref slot = Frame__getlocal_noproxy(self, name); - if(slot == NULL) return 0; // bad slot - *slot = *val; - return 1; + if(self->locals->type == tp_locals) { + self = self->locals->_ptr; + } else { + assert(self->locals->type == tp_dict); + return py_dict_setitem(self->locals, py_name2ref(name), val); + } } + py_Ref slot = Frame__getlocal_noproxy(self, name); + if(slot == NULL) return false; // bad slot + *slot = *val; + return true; } int Frame__dellocal(Frame* self, py_Name name) { if(self->is_locals_proxy) { - py_StackRef p0 = py_peek(0); - py_push(self->locals); - py_pushmethod(__delitem__); - py_push(py_name2ref(name)); - bool ok = py_vectorcall(1, 0); - if(!ok) { - if(py_matchexc(tp_KeyError)) { - py_clearexc(p0); - return 0; - } - return -1; + if(self->locals->type == tp_locals) { + self = self->locals->_ptr; + } else { + assert(self->locals->type == tp_dict); + return py_dict_delitem(self->locals, py_name2ref(name)); } - return 1; - } else { - py_Ref slot = Frame__getlocal_noproxy(self, name); - if(slot == NULL) return 0; // bad slot - if(py_isnil(slot)) { - UnboundLocalError(name); - return -1; - } - py_newnil(slot); - return 1; } + py_Ref slot = Frame__getlocal_noproxy(self, name); + if(slot == NULL) return 0; // bad slot + if(py_isnil(slot)) { + UnboundLocalError(name); + return -1; + } + py_newnil(slot); + return 1; } py_StackRef Frame__getlocal_noproxy(Frame* self, py_Name name) { assert(!self->is_locals_proxy); - return FastLocals__try_get_by_name(self->locals, self->co, name); + int index = c11_smallmap_n2i__get(&self->co->varnames_inv, name, -1); + if(index == -1) return NULL; + return &self->locals[index]; } py_Ref Frame__getclosure(Frame* self, py_Name name) { diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index 933b78bc..2f7ecf0e 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -127,7 +127,7 @@ void VM__ctor(VM* self) { validate(tp_Exception, pk_Exception__register()); validate(tp_bytes, pk_bytes__register()); validate(tp_namedict, pk_namedict__register()); - validate(tp_locals, pk_locals__register()); + validate(tp_locals, pk_newtype("locals", tp_object, NULL, NULL, false, true)); validate(tp_code, pk_code__register()); validate(tp_dict, pk_dict__register()); @@ -258,7 +258,7 @@ void VM__dtor(VM* self) { ModuleDict__dtor(&self->modules); TypeList__dtor(&self->types); FixedMemoryPool__dtor(&self->pool_frame); - ValueStack__clear(&self->stack); + ValueStack__dtor(&self->stack); InternedNames__dtor(&self->names); } diff --git a/src/public/modules.c b/src/public/modules.c index c6491157..450ec2e2 100644 --- a/src/public/modules.c +++ b/src/public/modules.c @@ -511,11 +511,17 @@ void py_newlocals(py_Ref out) { py_newglobals(out); return; } - if(!frame->is_locals_proxy) { - pk_mappingproxy__locals(out, frame); - } else { - *out = *frame->locals; + if(frame->is_locals_proxy) { + if(frame->locals->type == tp_locals) { + frame = frame->locals->_ptr; + } else { + assert(frame->locals->type == tp_dict); + *out = *frame->locals; + return; + } } + FastLocals__to_dict(frame->locals, frame->co); + py_assign(out, py_retval()); } static bool _builtins_execdyn(const char* title, int argc, py_Ref argv, enum py_CompileMode mode) { diff --git a/src/public/py_mappingproxy.c b/src/public/py_mappingproxy.c index 343d8c4a..174c6d81 100644 --- a/src/public/py_mappingproxy.c +++ b/src/public/py_mappingproxy.c @@ -116,59 +116,3 @@ void pk_mappingproxy__locals(py_Ref out, Frame* frame) { // locals() will expire when the frame is destroyed out->_ptr = frame; } - -static bool locals__getitem__(int argc, py_Ref argv) { - PY_CHECK_ARGC(2); - PY_CHECK_ARG_TYPE(1, tp_str); - Frame* frame = argv->_ptr; - py_Name name = py_namev(py_tosv(py_arg(1))); - py_Ref slot = Frame__getlocal_noproxy(frame, 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* frame = argv->_ptr; - py_Name name = py_namev(py_tosv(py_arg(1))); - py_Ref slot = Frame__getlocal_noproxy(frame, 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* frame = argv->_ptr; - py_Name name = py_namev(py_tosv(py_arg(1))); - py_Ref res = Frame__getlocal_noproxy(frame, 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* frame = argv->_ptr; - py_Name name = py_namev(py_tosv(py_arg(1))); - py_Ref slot = Frame__getlocal_noproxy(frame, name); - py_newbool(py_retval(), slot && !py_isnil(slot)); - return true; -} - -py_Type pk_locals__register() { - py_Type type = pk_newtype("locals", tp_object, 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__); - py_newnone(py_tpgetmagic(type, __hash__)); - return type; -} \ No newline at end of file