Browse Source

add `RELOAD_MODE`

blueloveTH 9 months ago
parent
commit
0b09246a6d

+ 16 - 1
include/pocketpy/interpreter/typeinfo.h

@@ -25,4 +25,19 @@ typedef struct py_TypeInfo {
 
 py_TypeInfo* pk_typeinfo(py_Type type);
 py_ItemRef pk_tpfindname(py_TypeInfo* ti, py_Name name);
-#define pk_tpfindmagic pk_tpfindname
+#define pk_tpfindmagic pk_tpfindname
+
+py_Type pk_newtype(const char* name,
+                   py_Type base,
+                   const py_GlobalRef module,
+                   void (*dtor)(void*),
+                   bool is_python,
+                   bool is_sealed);
+
+
+py_Type pk_newtypewithmode(py_Name name,
+                   py_Type base,
+                   const py_GlobalRef module,
+                   void (*dtor)(void*),
+                   bool is_python,
+                   bool is_sealed, enum py_CompileMode mode);

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

@@ -100,13 +100,6 @@ typedef enum FrameResult {
 
 FrameResult VM__run_top_frame(VM* self);
 
-py_Type pk_newtype(const char* name,
-                   py_Type base,
-                   const py_GlobalRef module,
-                   void (*dtor)(void*),
-                   bool is_python,
-                   bool is_sealed);
-
 FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall);
 
 const char* pk_opname(Opcode op);

+ 2 - 1
include/pocketpy/pocketpy.h

@@ -92,7 +92,8 @@ typedef bool (*py_CFunction)(int argc, py_StackRef argv) PY_RAISE PY_RETURN;
 /// + `EXEC_MODE`: for statements.
 /// + `EVAL_MODE`: for expressions.
 /// + `SINGLE_MODE`: for REPL or jupyter notebook execution.
-enum py_CompileMode { EXEC_MODE, EVAL_MODE, SINGLE_MODE };
+/// + `RELOAD_MODE`: for reloading a module without allocating new types if possible.
+enum py_CompileMode { EXEC_MODE, EVAL_MODE, SINGLE_MODE, RELOAD_MODE };
 
 /************* Global Setup *************/
 

+ 7 - 6
src/interpreter/ceval.c

@@ -1042,12 +1042,13 @@ FrameResult VM__run_top_frame(VM* self) {
                     goto __ERROR;
                 }
 
-                py_Type type = pk_newtype(py_name2str(name),
-                                          base,
-                                          frame->module,
-                                          NULL,
-                                          base_ti->is_python,
-                                          false);
+                py_Type type = pk_newtypewithmode(name,
+                                                  base,
+                                                  frame->module,
+                                                  NULL,
+                                                  base_ti->is_python,
+                                                  false,
+                                                  frame->co->src->mode);
                 PUSH(py_tpobject(type));
                 self->curr_class = TOP();
                 DISPATCH();

+ 76 - 0
src/interpreter/typeinfo.c

@@ -46,4 +46,80 @@ const char* py_tpname(py_Type type) {
 
 py_TypeInfo* pk_typeinfo(py_Type type) {
     return c11__getitem(TypePointer, &pk_current_vm->types, type).ti;
+}
+
+static void py_TypeInfo__common_init(py_Name name,
+                                     py_Type base,
+                                     py_Type index,
+                                     const py_GlobalRef module,
+                                     void (*dtor)(void*),
+                                     bool is_python,
+                                     bool is_sealed,
+                                     py_TypeInfo* self) {
+    py_TypeInfo* base_ti = base ? pk_typeinfo(base) : NULL;
+    if(base_ti && base_ti->is_sealed) {
+        c11__abort("type '%s' is not an acceptable base type", py_name2str(base_ti->name));
+    }
+
+    memset(self, 0, sizeof(py_TypeInfo));
+    self->name = name;
+    self->index = index;
+    self->base = base;
+    self->base_ti = base_ti;
+
+    self->self = *py_retval();
+    self->module = module ? module : py_NIL();
+    self->annotations = *py_NIL();
+
+    if(!dtor && base) dtor = base_ti->dtor;
+    self->is_python = is_python;
+    self->is_sealed = is_sealed;
+    self->dtor = dtor;
+}
+
+py_Type pk_newtype(const char* name,
+                   py_Type base,
+                   const py_GlobalRef module,
+                   void (*dtor)(void*),
+                   bool is_python,
+                   bool is_sealed) {
+    py_Type index = pk_current_vm->types.length;
+    py_TypeInfo* self = py_newobject(py_retval(), tp_type, -1, sizeof(py_TypeInfo));
+    py_TypeInfo__common_init(py_name(name), base, index, module, dtor, is_python, is_sealed, self);
+    TypePointer* pointer = c11_vector__emplace(&pk_current_vm->types);
+    pointer->ti = self;
+    pointer->dtor = self->dtor;
+    return index;
+}
+
+py_Type pk_newtypewithmode(py_Name name,
+                           py_Type base,
+                           const py_GlobalRef module,
+                           void (*dtor)(void*),
+                           bool is_python,
+                           bool is_sealed,
+                           enum py_CompileMode mode) {
+    if(mode == RELOAD_MODE && module != NULL) {
+        py_ItemRef old_class = py_getdict(module, name);
+        if(old_class != NULL && py_istype(old_class, tp_type)) {
+            NameDict* old_dict = PyObject__dict(old_class->_obj);
+            NameDict__clear(old_dict);
+            py_TypeInfo* self = py_touserdata(old_class);
+            py_Type index = self->index;
+            py_TypeInfo__common_init(name, base, index, module, dtor, is_python, is_sealed, self);
+            TypePointer* pointer = c11__at(TypePointer, &pk_current_vm->types, index);
+            pointer->ti = self;
+            pointer->dtor = self->dtor;
+            return index;
+        }
+    }
+
+    return pk_newtype(py_name2str(name), base, module, dtor, is_python, is_sealed);
+}
+
+py_Type py_newtype(const char* name, py_Type base, const py_GlobalRef module, void (*dtor)(void*)) {
+    if(strlen(name) == 0) c11__abort("type name cannot be empty");
+    py_Type type = pk_newtype(name, base, module, dtor, false, false);
+    if(module) py_setdict(module, py_name(name), py_tpobject(type));
+    return type;
 }

+ 0 - 41
src/interpreter/vm.c

@@ -364,47 +364,6 @@ bool pk__normalize_index(int* index, int length) {
     return true;
 }
 
-py_Type pk_newtype(const char* name,
-                   py_Type base,
-                   const py_GlobalRef module,
-                   void (*dtor)(void*),
-                   bool is_python,
-                   bool is_sealed) {
-    py_Type index = pk_current_vm->types.length;
-    py_TypeInfo* self = py_newobject(py_retval(), tp_type, -1, sizeof(py_TypeInfo));
-    py_TypeInfo* base_ti = base ? pk_typeinfo(base) : NULL;
-    if(base_ti && base_ti->is_sealed) {
-        c11__abort("type '%s' is not an acceptable base type", py_name2str(base_ti->name));
-    }
-
-    memset(self, 0, sizeof(py_TypeInfo));
-    self->name = py_name(name);
-    self->index = index;
-    self->base = base;
-    self->base_ti = base_ti;
-
-    self->self = *py_retval();
-    self->module = module ? module : py_NIL();
-    self->annotations = *py_NIL();
-
-    if(!dtor && base) dtor = base_ti->dtor;
-    self->is_python = is_python;
-    self->is_sealed = is_sealed;
-    self->dtor = dtor;
-
-    TypePointer* pointer = c11_vector__emplace(&pk_current_vm->types);
-    pointer->ti = self;
-    pointer->dtor = dtor;
-    return index;
-}
-
-py_Type py_newtype(const char* name, py_Type base, const py_GlobalRef module, void (*dtor)(void*)) {
-    if(strlen(name) == 0) c11__abort("type name cannot be empty");
-    py_Type type = pk_newtype(name, base, module, dtor, false, false);
-    if(module) py_setdict(module, py_name(name), py_tpobject(type));
-    return type;
-}
-
 static bool
     prepare_py_call(py_TValue* buffer, py_Ref argv, py_Ref p1, int kwargc, const FuncDecl* decl) {
     const CodeObject* co = &decl->code;

+ 1 - 1
src/public/modules.c

@@ -176,7 +176,7 @@ bool py_importlib_reload(py_GlobalRef module) {
     }
     c11_string__delete(slashed_path);
     if(data == NULL) return ImportError("module '%v' not found", path);
-    bool ok = py_exec(data, filename->data, EXEC_MODE, module);
+    bool ok = py_exec(data, filename->data, RELOAD_MODE, module);
     c11_string__delete(filename);
     PK_FREE(data);
     py_assign(py_retval(), module);