improve module

This commit is contained in:
blueloveTH 2025-06-22 13:37:20 +08:00
parent 0b09246a6d
commit 68a2186728
10 changed files with 80 additions and 39 deletions

View File

@ -34,6 +34,13 @@ typedef struct TypePointer {
py_Dtor dtor; py_Dtor dtor;
} TypePointer; } TypePointer;
typedef struct py_ModuleInfo {
c11_string* name;
c11_string* package;
c11_string* path;
} py_ModuleInfo;
typedef struct VM { typedef struct VM {
py_Frame* top_frame; py_Frame* top_frame;
@ -139,6 +146,7 @@ py_Type pk_nativefunc__register();
py_Type pk_boundmethod__register(); py_Type pk_boundmethod__register();
py_Type pk_range__register(); py_Type pk_range__register();
py_Type pk_range_iterator__register(); py_Type pk_range_iterator__register();
py_Type pk_module__register();
py_Type pk_BaseException__register(); py_Type pk_BaseException__register();
py_Type pk_Exception__register(); py_Type pk_Exception__register();
py_Type pk_StopIteration__register(); py_Type pk_StopIteration__register();

View File

@ -406,6 +406,8 @@ PK_API py_ItemRef py_emplacedict(py_Ref self, py_Name name);
/// NOTE: Be careful if `f` modifies the object's `__dict__`. /// NOTE: Be careful if `f` modifies the object's `__dict__`.
PK_API bool PK_API bool
py_applydict(py_Ref self, bool (*f)(py_Name name, py_Ref val, void* ctx), void* ctx) PY_RAISE; py_applydict(py_Ref self, bool (*f)(py_Name name, py_Ref val, void* ctx), void* ctx) PY_RAISE;
/// Clear the object's `__dict__`. This function is dangerous.
PK_API void py_cleardict(py_Ref self);
/// Get the i-th slot of the object. /// Get the i-th slot of the object.
/// The object must have slots and `i` must be in valid range. /// The object must have slots and `i` must be in valid range.

View File

@ -50,7 +50,7 @@ void VM__ctor(VM* self) {
const static BinTreeConfig modules_config = { const static BinTreeConfig modules_config = {
.f_cmp = BinTree__cmp_cstr, .f_cmp = BinTree__cmp_cstr,
.need_free_key = true, .need_free_key = false,
}; };
BinTree__ctor(&self->modules, c11_strdup(""), py_NIL(), &modules_config); BinTree__ctor(&self->modules, c11_strdup(""), py_NIL(), &modules_config);
c11_vector__ctor(&self->types, sizeof(TypePointer)); c11_vector__ctor(&self->types, sizeof(TypePointer));
@ -114,7 +114,7 @@ void VM__ctor(VM* self) {
validate(tp_slice, pk_slice__register()); validate(tp_slice, pk_slice__register());
validate(tp_range, pk_range__register()); validate(tp_range, pk_range__register());
validate(tp_range_iterator, pk_range_iterator__register()); validate(tp_range_iterator, pk_range_iterator__register());
validate(tp_module, pk_newtype("module", tp_object, NULL, NULL, false, true)); validate(tp_module, pk_module__register());
validate(tp_function, pk_function__register()); validate(tp_function, pk_function__register());
validate(tp_nativefunc, pk_nativefunc__register()); validate(tp_nativefunc, pk_nativefunc__register());

View File

@ -37,8 +37,8 @@ void pk_print_stack(VM* self, py_Frame* frame, Bytecode byte) {
break; break;
} }
case tp_module: { case tp_module: {
py_Ref path = py_getdict(p, __path__); py_ModuleInfo* mi = py_touserdata(p);
pk_sprintf(&buf, "<module '%v'>", py_tosv(path)); pk_sprintf(&buf, "<module '%v'>", c11_string__sv(mi->path));
break; break;
} }
default: { default: {

View File

@ -66,10 +66,10 @@ static void c11_sbuf__write_type_path(c11_sbuf* path_buf, py_Type type) {
c11_sbuf__write_cstr(path_buf, py_name2str(ti->name)); c11_sbuf__write_cstr(path_buf, py_name2str(ti->name));
return; return;
} }
const char* mod_path = py_tostr(py_getdict(ti->module, __path__)); py_ModuleInfo* mi = py_touserdata(ti->module);
c11_sbuf__write_cstr(path_buf, mod_path); c11_sbuf__write_sv(path_buf, c11_string__sv(mi->path));
c11_sbuf__write_char(path_buf, '.'); c11_sbuf__write_char(path_buf, '.');
c11_sbuf__write_cstr(path_buf, py_name2str(ti->name)); c11_sbuf__write_sv(path_buf, py_name2sv(ti->name));
} }
static void pkl__emit_op(PickleObject* buf, PickleOp op) { static void pkl__emit_op(PickleObject* buf, PickleOp op) {

View File

@ -22,49 +22,67 @@ py_Ref py_getglobal(py_Name name) { return py_getdict(pk_current_vm->main, name)
void py_setglobal(py_Name name, py_Ref val) { py_setdict(pk_current_vm->main, name, val); } void py_setglobal(py_Name name, py_Ref val) { py_setdict(pk_current_vm->main, name, val); }
py_Ref py_newmodule(const char* path) { static void py_ModuleInfo__dtor(py_ModuleInfo* mi) {
ManagedHeap* heap = &pk_current_vm->heap; c11_string__delete(mi->name);
c11_string__delete(mi->package);
c11_string__delete(mi->path);
}
static bool module__name__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
py_ModuleInfo* mi = py_touserdata(argv);
py_newstrv(py_retval(), c11_string__sv(mi->name));
return true;
}
static bool module__package__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
py_ModuleInfo* mi = py_touserdata(argv);
py_newstrv(py_retval(), c11_string__sv(mi->package));
return true;
}
static bool module__path__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
py_ModuleInfo* mi = py_touserdata(argv);
py_newstrv(py_retval(), c11_string__sv(mi->path));
return true;
}
py_Type pk_module__register() {
py_Type type = pk_newtype("module", tp_object, NULL, (py_Dtor)py_ModuleInfo__dtor, false, true);
py_bindproperty(type, "__name__", module__name__, NULL);
py_bindproperty(type, "__package__", module__package__, NULL);
py_bindproperty(type, "__path__", module__path__, NULL);
return type;
}
py_Ref py_newmodule(const char* path) {
int path_len = strlen(path); int path_len = strlen(path);
if(path_len > PK_MAX_MODULE_PATH_LEN) c11__abort("module path too long: %s", path); if(path_len > PK_MAX_MODULE_PATH_LEN) c11__abort("module path too long: %s", path);
if(path_len == 0) c11__abort("module path cannot be empty"); if(path_len == 0) c11__abort("module path cannot be empty");
py_Ref r0 = py_pushtmp(); py_ModuleInfo* mi = py_newobject(py_retval(), tp_module, -1, sizeof(py_ModuleInfo));
py_Ref r1 = py_pushtmp();
*r0 = (py_TValue){
.type = tp_module,
.is_ptr = true,
._obj = ManagedHeap__new(heap, tp_module, -1, 0),
};
int last_dot = c11_sv__rindex((c11_sv){path, path_len}, '.'); int last_dot = c11_sv__rindex((c11_sv){path, path_len}, '.');
if(last_dot == -1) { if(last_dot == -1) {
py_newstr(r1, path); mi->name = c11_string__new(path);
py_setdict(r0, __name__, r1); mi->package = c11_string__new("");
py_newstr(r1, "");
py_setdict(r0, __package__, r1);
} else { } else {
const char* start = path + last_dot + 1; const char* start = path + last_dot + 1;
py_newstr(r1, start); mi->name = c11_string__new(start);
py_setdict(r0, __name__, r1); mi->package = c11_string__new2(path, last_dot);
py_newstrv(r1, (c11_sv){path, last_dot});
py_setdict(r0, __package__, r1);
} }
py_newstr(r1, path); mi->path = c11_string__new(path);
py_setdict(r0, __path__, r1); path = mi->path->data;
// we do not allow override in order to avoid memory leak // we do not allow override in order to avoid memory leak
// it is because Module objects are not garbage collected // it is because Module objects are not garbage collected
bool exists = BinTree__contains(&pk_current_vm->modules, (void*)path); bool exists = BinTree__contains(&pk_current_vm->modules, (void*)path);
if(exists) c11__abort("module '%s' already exists", path); if(exists) c11__abort("module '%s' already exists", path);
// convert to a weak (const char*) BinTree__set(&pk_current_vm->modules, (void*)path, py_retval());
path = py_tostr(py_getdict(r0, __path__));
BinTree__set(&pk_current_vm->modules, c11_strdup(path), r0);
py_shrink(2);
return py_getmodule(path); return py_getmodule(path);
} }
@ -84,8 +102,8 @@ int py_import(const char* path_cstr) {
c11_sv top_filename = c11_string__sv(vm->top_frame->co->src->filename); c11_sv top_filename = c11_string__sv(vm->top_frame->co->src->filename);
int is_init = c11_sv__endswith(top_filename, (c11_sv){"__init__.py", 11}); int is_init = c11_sv__endswith(top_filename, (c11_sv){"__init__.py", 11});
py_Ref package = py_getdict(vm->top_frame->module, __path__); py_ModuleInfo* mi = py_touserdata(vm->top_frame->module);
c11_sv package_sv = py_tosv(package); c11_sv package_sv = c11_string__sv(mi->path);
if(package_sv.size == 0) { if(package_sv.size == 0) {
return ImportError("attempted relative import with no known parent package"); return ImportError("attempted relative import with no known parent package");
} }
@ -165,7 +183,8 @@ __SUCCESS:
bool py_importlib_reload(py_GlobalRef module) { bool py_importlib_reload(py_GlobalRef module) {
VM* vm = pk_current_vm; VM* vm = pk_current_vm;
c11_sv path = py_tosv(py_getdict(module, __path__)); py_ModuleInfo* mi = py_touserdata(module);
c11_sv path = c11_string__sv(mi->path);
c11_string* slashed_path = c11_sv__replace(path, '.', PK_PLATFORM_SEP); c11_string* slashed_path = c11_sv__replace(path, '.', PK_PLATFORM_SEP);
c11_string* filename = c11_string__new3("%s.py", slashed_path->data); c11_string* filename = c11_string__new3("%s.py", slashed_path->data);
char* data = vm->callbacks.importfile(filename->data); char* data = vm->callbacks.importfile(filename->data);
@ -176,6 +195,7 @@ bool py_importlib_reload(py_GlobalRef module) {
} }
c11_string__delete(slashed_path); c11_string__delete(slashed_path);
if(data == NULL) return ImportError("module '%v' not found", path); if(data == NULL) return ImportError("module '%v' not found", path);
py_cleardict(module);
bool ok = py_exec(data, filename->data, RELOAD_MODE, module); bool ok = py_exec(data, filename->data, RELOAD_MODE, module);
c11_string__delete(filename); c11_string__delete(filename);
PK_FREE(data); PK_FREE(data);

View File

@ -104,8 +104,8 @@ static bool type__module__(int argc, py_Ref argv) {
if(py_isnil(ti->module)) { if(py_isnil(ti->module)) {
py_newnone(py_retval()); py_newnone(py_retval());
} else { } else {
py_Ref path = py_getdict(ti->module, __path__); py_ModuleInfo* mi = py_touserdata(ti->module);
py_assign(py_retval(), path); py_newstrv(py_retval(), c11_string__sv(mi->path));
} }
return true; return true;
} }

View File

@ -166,10 +166,10 @@ bool py_getattr(py_Ref self, py_Name name) {
} }
if(self->type == tp_module) { if(self->type == tp_module) {
py_Ref path = py_getdict(self, __path__); py_ModuleInfo* mi = py_touserdata(self);
c11_sbuf buf; c11_sbuf buf;
c11_sbuf__ctor(&buf); c11_sbuf__ctor(&buf);
pk_sprintf(&buf, "%v.%n", py_tosv(path), name); pk_sprintf(&buf, "%v.%n", c11_string__sv(mi->path), name);
c11_string* new_path = c11_sbuf__submit(&buf); c11_string* new_path = c11_sbuf__submit(&buf);
int res = py_import(new_path->data); int res = py_import(new_path->data);
c11_string__delete(new_path); c11_string__delete(new_path);

View File

@ -35,6 +35,12 @@ bool py_applydict(py_Ref self, bool (*f)(py_Name, py_Ref, void*), void* ctx) {
return true; return true;
} }
void py_cleardict(py_Ref self) {
assert(self && self->is_ptr);
NameDict* dict = PyObject__dict(self->_obj);
NameDict__clear(dict);
}
bool py_deldict(py_Ref self, py_Name name) { bool py_deldict(py_Ref self, py_Name name) {
assert(self && self->is_ptr); assert(self && self->is_ptr);
return NameDict__del(PyObject__dict(self->_obj), name); return NameDict__del(PyObject__dict(self->_obj), name);

View File

@ -23,6 +23,11 @@ assert get_value_2() == '123'
from test3.a.b import value from test3.a.b import value
assert value == 1 assert value == 1
from test2.utils import r
assert r.__name__ == 'r'
assert r.__package__ == 'test2.utils'
assert r.__path__ == 'test2.utils.r'
def f(): def f():
import math as m import math as m
assert m.pi > 3 assert m.pi > 3