mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
improve module
This commit is contained in:
parent
0b09246a6d
commit
68a2186728
@ -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();
|
||||||
|
@ -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.
|
||||||
|
@ -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());
|
||||||
|
@ -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: {
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user