mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-19 19:10:17 +00:00
improve module
This commit is contained in:
parent
0b09246a6d
commit
68a2186728
@ -34,6 +34,13 @@ typedef struct TypePointer {
|
||||
py_Dtor dtor;
|
||||
} TypePointer;
|
||||
|
||||
typedef struct py_ModuleInfo {
|
||||
c11_string* name;
|
||||
c11_string* package;
|
||||
c11_string* path;
|
||||
} py_ModuleInfo;
|
||||
|
||||
|
||||
typedef struct VM {
|
||||
py_Frame* top_frame;
|
||||
|
||||
@ -139,6 +146,7 @@ py_Type pk_nativefunc__register();
|
||||
py_Type pk_boundmethod__register();
|
||||
py_Type pk_range__register();
|
||||
py_Type pk_range_iterator__register();
|
||||
py_Type pk_module__register();
|
||||
py_Type pk_BaseException__register();
|
||||
py_Type pk_Exception__register();
|
||||
py_Type pk_StopIteration__register();
|
||||
|
@ -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__`.
|
||||
PK_API bool
|
||||
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.
|
||||
/// The object must have slots and `i` must be in valid range.
|
||||
|
@ -50,7 +50,7 @@ void VM__ctor(VM* self) {
|
||||
|
||||
const static BinTreeConfig modules_config = {
|
||||
.f_cmp = BinTree__cmp_cstr,
|
||||
.need_free_key = true,
|
||||
.need_free_key = false,
|
||||
};
|
||||
BinTree__ctor(&self->modules, c11_strdup(""), py_NIL(), &modules_config);
|
||||
c11_vector__ctor(&self->types, sizeof(TypePointer));
|
||||
@ -114,7 +114,7 @@ void VM__ctor(VM* self) {
|
||||
validate(tp_slice, pk_slice__register());
|
||||
validate(tp_range, pk_range__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_nativefunc, pk_nativefunc__register());
|
||||
|
@ -37,8 +37,8 @@ void pk_print_stack(VM* self, py_Frame* frame, Bytecode byte) {
|
||||
break;
|
||||
}
|
||||
case tp_module: {
|
||||
py_Ref path = py_getdict(p, __path__);
|
||||
pk_sprintf(&buf, "<module '%v'>", py_tosv(path));
|
||||
py_ModuleInfo* mi = py_touserdata(p);
|
||||
pk_sprintf(&buf, "<module '%v'>", c11_string__sv(mi->path));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
@ -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));
|
||||
return;
|
||||
}
|
||||
const char* mod_path = py_tostr(py_getdict(ti->module, __path__));
|
||||
c11_sbuf__write_cstr(path_buf, mod_path);
|
||||
py_ModuleInfo* mi = py_touserdata(ti->module);
|
||||
c11_sbuf__write_sv(path_buf, c11_string__sv(mi->path));
|
||||
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) {
|
||||
|
@ -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); }
|
||||
|
||||
py_Ref py_newmodule(const char* path) {
|
||||
ManagedHeap* heap = &pk_current_vm->heap;
|
||||
static void py_ModuleInfo__dtor(py_ModuleInfo* mi) {
|
||||
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);
|
||||
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");
|
||||
|
||||
py_Ref r0 = py_pushtmp();
|
||||
py_Ref r1 = py_pushtmp();
|
||||
|
||||
*r0 = (py_TValue){
|
||||
.type = tp_module,
|
||||
.is_ptr = true,
|
||||
._obj = ManagedHeap__new(heap, tp_module, -1, 0),
|
||||
};
|
||||
py_ModuleInfo* mi = py_newobject(py_retval(), tp_module, -1, sizeof(py_ModuleInfo));
|
||||
|
||||
int last_dot = c11_sv__rindex((c11_sv){path, path_len}, '.');
|
||||
if(last_dot == -1) {
|
||||
py_newstr(r1, path);
|
||||
py_setdict(r0, __name__, r1);
|
||||
py_newstr(r1, "");
|
||||
py_setdict(r0, __package__, r1);
|
||||
mi->name = c11_string__new(path);
|
||||
mi->package = c11_string__new("");
|
||||
} else {
|
||||
const char* start = path + last_dot + 1;
|
||||
py_newstr(r1, start);
|
||||
py_setdict(r0, __name__, r1);
|
||||
py_newstrv(r1, (c11_sv){path, last_dot});
|
||||
py_setdict(r0, __package__, r1);
|
||||
mi->name = c11_string__new(start);
|
||||
mi->package = c11_string__new2(path, last_dot);
|
||||
}
|
||||
|
||||
py_newstr(r1, path);
|
||||
py_setdict(r0, __path__, r1);
|
||||
mi->path = c11_string__new(path);
|
||||
path = mi->path->data;
|
||||
|
||||
// we do not allow override in order to avoid memory leak
|
||||
// it is because Module objects are not garbage collected
|
||||
bool exists = BinTree__contains(&pk_current_vm->modules, (void*)path);
|
||||
if(exists) c11__abort("module '%s' already exists", path);
|
||||
|
||||
// convert to a weak (const char*)
|
||||
path = py_tostr(py_getdict(r0, __path__));
|
||||
BinTree__set(&pk_current_vm->modules, c11_strdup(path), r0);
|
||||
|
||||
py_shrink(2);
|
||||
BinTree__set(&pk_current_vm->modules, (void*)path, py_retval());
|
||||
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);
|
||||
int is_init = c11_sv__endswith(top_filename, (c11_sv){"__init__.py", 11});
|
||||
|
||||
py_Ref package = py_getdict(vm->top_frame->module, __path__);
|
||||
c11_sv package_sv = py_tosv(package);
|
||||
py_ModuleInfo* mi = py_touserdata(vm->top_frame->module);
|
||||
c11_sv package_sv = c11_string__sv(mi->path);
|
||||
if(package_sv.size == 0) {
|
||||
return ImportError("attempted relative import with no known parent package");
|
||||
}
|
||||
@ -165,7 +183,8 @@ __SUCCESS:
|
||||
|
||||
bool py_importlib_reload(py_GlobalRef module) {
|
||||
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* filename = c11_string__new3("%s.py", slashed_path->data);
|
||||
char* data = vm->callbacks.importfile(filename->data);
|
||||
@ -176,6 +195,7 @@ bool py_importlib_reload(py_GlobalRef module) {
|
||||
}
|
||||
c11_string__delete(slashed_path);
|
||||
if(data == NULL) return ImportError("module '%v' not found", path);
|
||||
py_cleardict(module);
|
||||
bool ok = py_exec(data, filename->data, RELOAD_MODE, module);
|
||||
c11_string__delete(filename);
|
||||
PK_FREE(data);
|
||||
|
@ -104,8 +104,8 @@ static bool type__module__(int argc, py_Ref argv) {
|
||||
if(py_isnil(ti->module)) {
|
||||
py_newnone(py_retval());
|
||||
} else {
|
||||
py_Ref path = py_getdict(ti->module, __path__);
|
||||
py_assign(py_retval(), path);
|
||||
py_ModuleInfo* mi = py_touserdata(ti->module);
|
||||
py_newstrv(py_retval(), c11_string__sv(mi->path));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -166,10 +166,10 @@ bool py_getattr(py_Ref self, py_Name name) {
|
||||
}
|
||||
|
||||
if(self->type == tp_module) {
|
||||
py_Ref path = py_getdict(self, __path__);
|
||||
py_ModuleInfo* mi = py_touserdata(self);
|
||||
c11_sbuf 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);
|
||||
int res = py_import(new_path->data);
|
||||
c11_string__delete(new_path);
|
||||
|
@ -35,6 +35,12 @@ bool py_applydict(py_Ref self, bool (*f)(py_Name, py_Ref, void*), void* ctx) {
|
||||
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) {
|
||||
assert(self && self->is_ptr);
|
||||
return NameDict__del(PyObject__dict(self->_obj), name);
|
||||
|
@ -23,6 +23,11 @@ assert get_value_2() == '123'
|
||||
from test3.a.b import value
|
||||
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():
|
||||
import math as m
|
||||
assert m.pi > 3
|
||||
|
Loading…
x
Reference in New Issue
Block a user