blueloveTH 1 an în urmă
părinte
comite
9af9d228dd

+ 5 - 1
include/pocketpy/interpreter/frame.h

@@ -57,10 +57,14 @@ int Frame__getglobal(Frame* self, py_Name name) PY_RAISE PY_RETURN;
 bool Frame__setglobal(Frame* self, py_Name name, py_TValue* val) PY_RAISE;
 int Frame__delglobal(Frame* self, py_Name name) PY_RAISE;
 
-py_Ref Frame__getclosure(Frame* self, py_Name name);
+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;
+int Frame__dellocal(Frame* self, py_Name name) PY_RAISE;
 
+py_Ref Frame__getclosure(Frame* self, py_Name name);
 py_StackRef Frame__getlocal_noproxy(Frame* self, py_Name name);
 
+py_StackRef Frame__locals_sp(Frame* self);
 
 int Frame__prepare_jump_exception_handler(Frame* self, ValueStack*);
 

+ 1 - 0
include/pocketpy/interpreter/vm.h

@@ -96,6 +96,7 @@ bool pk_loadmethod(py_StackRef self, py_Name name);
 bool pk_callmagic(py_Name name, int argc, py_Ref argv);
 
 bool pk_exec(CodeObject* co, py_Ref module);
+bool pk_execdyn(CodeObject* co, py_Ref module, py_Ref globals, py_Ref locals);
 
 /// Assumes [a, b] are on the stack, performs a binary op.
 /// The result is stored in `self->last_retval`.

+ 7 - 2
src/interpreter/ceval.c

@@ -194,6 +194,7 @@ FrameResult VM__run_top_frame(VM* self) {
                 DISPATCH();
                 /*****************************************/
             case OP_LOAD_FAST: {
+                assert(!frame->is_locals_proxy);
                 PUSH(&frame->locals[byte.arg]);
                 if(py_isnil(TOP())) {
                     py_Name name = c11__getitem(uint16_t, &frame->co->varnames, byte.arg);
@@ -220,7 +221,6 @@ FrameResult VM__run_top_frame(VM* self) {
                         }
                     }
                 }
-                // `LOAD_
                 // globals
                 if(py_getitem(&frame->p0[0], TOP())) {
                     py_assign(TOP(), py_retval());
@@ -343,7 +343,11 @@ FrameResult VM__run_top_frame(VM* self) {
                 TypeError("'%t' object is not subscriptable", SECOND()->type);
                 goto __ERROR;
             }
-            case OP_STORE_FAST: frame->locals[byte.arg] = POPX(); DISPATCH();
+            case OP_STORE_FAST: {
+                assert(!frame->is_locals_proxy);
+                frame->locals[byte.arg] = POPX();
+                DISPATCH();
+            }
             case OP_STORE_NAME: {
                 // assert(frame->is_dynamic);
                 py_Name name = byte.arg;
@@ -405,6 +409,7 @@ FrameResult VM__run_top_frame(VM* self) {
                 goto __ERROR;
             }
             case OP_DELETE_FAST: {
+                assert(!frame->is_locals_proxy);
                 py_Ref tmp = &frame->locals[byte.arg];
                 if(py_isnil(tmp)) {
                     py_Name name = c11__getitem(py_Name, &frame->co->varnames, byte.arg);

+ 74 - 3
src/interpreter/frame.c

@@ -79,7 +79,7 @@ int Frame__prepare_jump_exception_handler(Frame* self, ValueStack* _s) {
     }
     if(iblock < 0) return -1;
     UnwindTarget* uw = Frame__find_unwind_target(self, iblock);
-    _s->sp = (self->locals + uw->offset);  // unwind the stack
+    _s->sp = (Frame__locals_sp(self) + uw->offset);  // unwind the stack
     return c11__at(CodeBlock, &self->co->blocks, iblock)->end;
 }
 
@@ -95,10 +95,10 @@ void Frame__set_unwind_target(Frame* self, py_TValue* sp) {
     int iblock = Frame__iblock(self);
     UnwindTarget* existing = Frame__find_unwind_target(self, iblock);
     if(existing) {
-        existing->offset = sp - self->locals;
+        existing->offset = sp - Frame__locals_sp(self);
     } else {
         UnwindTarget* prev = self->uw_list;
-        self->uw_list = UnwindTarget__new(prev, iblock, sp - self->locals);
+        self->uw_list = UnwindTarget__new(prev, iblock, sp - Frame__locals_sp(self));
     }
 }
 
@@ -149,6 +149,77 @@ 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;
+        }
+        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;
+    }
+}
+
+int 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;
+    }
+}
+
+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;
+        }
+        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_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);

+ 8 - 4
src/interpreter/generator.c

@@ -28,10 +28,14 @@ static bool generator__next__(int argc, py_Ref argv) {
     if(ud->state == 2) return StopIteration();
 
     // reset frame->p0
-    int locals_offset = ud->frame->locals - ud->frame->p0;
-    ud->frame->p0 = py_peek(0);
-    ud->frame->locals = ud->frame->p0 + locals_offset;
-
+    if(!ud->frame->is_locals_proxy){
+        int locals_offset = ud->frame->locals - ud->frame->p0;
+        ud->frame->p0 = py_peek(0);
+        ud->frame->locals = ud->frame->p0 + locals_offset;
+    }else{
+        ud->frame->p0 = py_peek(0);
+    }
+    
     // restore the context
     py_Ref backup = py_getslot(argv, 0);
     int length = py_list_len(backup);

+ 26 - 9
src/public/exec.c

@@ -7,12 +7,11 @@
 #include "pocketpy/objects/object.h"
 #include "pocketpy/interpreter/vm.h"
 #include "pocketpy/compiler/compiler.h"
-
-static void code__gc_mark(void* ud) { CodeObject__gc_mark(ud); }
+#include <assert.h>
 
 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, code__gc_mark);
+    pk__tp_set_marker(type, (void (*)(void *))CodeObject__gc_mark);
     return type;
 }
 
@@ -57,16 +56,34 @@ bool pk_exec(CodeObject* co, py_Ref module) {
     assert(module->type == tp_module);
 
     py_StackRef sp = vm->stack.sp;
-    if(co->src->is_dynamic) sp -= 3;  // [globals, locals, code]
+    Frame* frame = Frame__new(co, sp, module, module, sp, false, false);
+    VM__push_frame(vm, frame);
+    FrameResult res = VM__run_top_frame(vm);
+    if(res == RES_ERROR) return false;
+    assert(res == RES_RETURN);
+    return true;
+}
+
+bool pk_execdyn(CodeObject* co, py_Ref module, py_Ref globals, py_Ref locals) {
+    VM* vm = pk_current_vm;
+    if(!module) module = &vm->main;
+    assert(module->type == tp_module);
+
+    py_StackRef sp = vm->stack.sp;
+    assert(globals != NULL && locals != NULL);
 
-    const bool is_p0_function = false;
-    const bool is_locals_proxy = true;
-    Frame* frame = Frame__new(co, sp, module, module, sp, is_p0_function, is_locals_proxy);
+    if(globals->type == tp_namedict) {
+        globals = py_getslot(globals, 0);
+        assert(globals->type == tp_module);
+    } else {
+        assert(globals->type == tp_dict);
+    }
+    Frame* frame = Frame__new(co, sp, module, globals, locals, false, true);
     VM__push_frame(vm, frame);
     FrameResult res = VM__run_top_frame(vm);
     if(res == RES_ERROR) return false;
-    if(res == RES_RETURN) return true;
-    c11__unreachable();
+    assert(res == RES_RETURN);
+    return true;
 }
 
 bool py_exec(const char* source, const char* filename, enum py_CompileMode mode, py_Ref module) {

+ 13 - 6
src/public/modules.c

@@ -501,7 +501,7 @@ void py_newglobals(py_Ref out) {
     if(frame->globals->type == tp_module) {
         pk_mappingproxy__namedict(out, frame->globals);
     } else {
-        *out = *frame->globals; // dict
+        *out = *frame->globals;  // dict
     }
 }
 
@@ -511,9 +511,9 @@ void py_newlocals(py_Ref out) {
         py_newglobals(out);
         return;
     }
-    if(!frame->is_locals_proxy){
+    if(!frame->is_locals_proxy) {
         pk_mappingproxy__locals(out, frame);
-    }else{
+    } else {
         *out = *frame->locals;
     }
 }
@@ -529,6 +529,7 @@ static bool _builtins_execdyn(const char* title, int argc, py_Ref argv, enum py_
             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();
@@ -538,6 +539,7 @@ static bool _builtins_execdyn(const char* title, int argc, py_Ref argv, enum py_
             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));
@@ -562,12 +564,15 @@ static bool _builtins_execdyn(const char* title, int argc, py_Ref argv, enum py_
     // [globals, locals, code]
     CodeObject* co = py_touserdata(code);
     if(!co->src->is_dynamic) {
+        py_shrink(3);
         if(argc != 1)
             return ValueError("code object is not dynamic, `globals` and `locals` must be None");
-        py_shrink(3);
     }
+
     Frame* frame = pk_current_vm->top_frame;
-    return pk_exec(co, frame ? frame->module : NULL);
+    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) {
@@ -787,7 +792,9 @@ static bool super__new__(int argc, py_Ref argv) {
                 Function* func = py_touserdata(callable);
                 if(func->clazz != NULL) {
                     class_arg = *(py_Type*)PyObject__userdata(func->clazz);
-                    if(frame->co->nlocals > 0) self_arg = &frame->locals[0];
+                    if(frame->co->nlocals > 0) {
+                        if(!frame->is_locals_proxy) self_arg = &frame->locals[0];
+                    }
                 }
             }
         }