mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 19:40:18 +00:00
...
This commit is contained in:
parent
a8dcecfbe2
commit
08d6a9a1ea
@ -53,7 +53,7 @@ When you do `import` a module, the VM will try to find it in the following order
|
|||||||
|
|
||||||
1. Search `vm->_modules`, if found, return it.
|
1. Search `vm->_modules`, if found, return it.
|
||||||
2. Search `vm->_lazy_modules`, if found, compile and execute it, then return it.
|
2. Search `vm->_lazy_modules`, if found, compile and execute it, then return it.
|
||||||
3. Search `vm->_path` and try to load it from file system.
|
3. Search the working directory and try to load it from file system via `read_file_cwd`.
|
||||||
|
|
||||||
|
|
||||||
### Filesystem hook
|
### Filesystem hook
|
||||||
|
@ -483,6 +483,10 @@ __NEXT_STEP:;
|
|||||||
_name = StrName(byte.arg);
|
_name = StrName(byte.arg);
|
||||||
PUSH(py_import(_name));
|
PUSH(py_import(_name));
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
|
TARGET(IMPORT_NAME_REL)
|
||||||
|
_name = StrName(byte.arg);
|
||||||
|
PUSH(py_import(_name, true));
|
||||||
|
DISPATCH();
|
||||||
TARGET(IMPORT_STAR)
|
TARGET(IMPORT_STAR)
|
||||||
_0 = POPX();
|
_0 = POPX();
|
||||||
for(auto& [name, value]: _0->attr().items()){
|
for(auto& [name, value]: _0->attr().items()){
|
||||||
|
@ -169,4 +169,10 @@ inline PyObject* const PY_BEGIN_CALL = (PyObject*)0b010011;
|
|||||||
inline PyObject* const PY_OP_CALL = (PyObject*)0b100011;
|
inline PyObject* const PY_OP_CALL = (PyObject*)0b100011;
|
||||||
inline PyObject* const PY_OP_YIELD = (PyObject*)0b110011;
|
inline PyObject* const PY_OP_YIELD = (PyObject*)0b110011;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
char kPlatformSep = '\\';
|
||||||
|
#else
|
||||||
|
char kPlatformSep = '/';
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
@ -505,9 +505,11 @@ __SUBSCR_END:
|
|||||||
|
|
||||||
Str _compile_import() {
|
Str _compile_import() {
|
||||||
if(name_scope() != NAME_GLOBAL) SyntaxError("import statement should be used in global scope");
|
if(name_scope() != NAME_GLOBAL) SyntaxError("import statement should be used in global scope");
|
||||||
|
Opcode op = OP_IMPORT_NAME;
|
||||||
|
if(match(TK("."))) op = OP_IMPORT_NAME_REL;
|
||||||
consume(TK("@id"));
|
consume(TK("@id"));
|
||||||
Str name = prev().str();
|
Str name = prev().str();
|
||||||
ctx()->emit(OP_IMPORT_NAME, StrName(name).index, prev().line);
|
ctx()->emit(op, StrName(name).index, prev().line);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,6 +95,7 @@ OPCODE(GET_ITER)
|
|||||||
OPCODE(FOR_ITER)
|
OPCODE(FOR_ITER)
|
||||||
/**************************/
|
/**************************/
|
||||||
OPCODE(IMPORT_NAME)
|
OPCODE(IMPORT_NAME)
|
||||||
|
OPCODE(IMPORT_NAME_REL)
|
||||||
OPCODE(IMPORT_STAR)
|
OPCODE(IMPORT_STAR)
|
||||||
/**************************/
|
/**************************/
|
||||||
OPCODE(UNPACK_SEQUENCE)
|
OPCODE(UNPACK_SEQUENCE)
|
||||||
|
@ -205,7 +205,7 @@ inline void init_builtins(VM* _vm) {
|
|||||||
_vm->bind__repr__(_vm->tp_object, [](VM* vm, PyObject* obj) {
|
_vm->bind__repr__(_vm->tp_object, [](VM* vm, PyObject* obj) {
|
||||||
if(is_tagged(obj)) FATAL_ERROR();
|
if(is_tagged(obj)) FATAL_ERROR();
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "<" << OBJ_NAME(vm->_t(obj)) << " object at " << std::hex << obj << ">";
|
ss << "<" << OBJ_NAME(vm->_t(obj)) << " object at 0x" << std::hex << obj << ">";
|
||||||
return VAR(ss.str());
|
return VAR(ss.str());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
71
src/vm.h
71
src/vm.h
@ -114,7 +114,6 @@ public:
|
|||||||
|
|
||||||
NameDict _modules; // loaded modules
|
NameDict _modules; // loaded modules
|
||||||
std::map<StrName, Str> _lazy_modules; // lazy loaded modules
|
std::map<StrName, Str> _lazy_modules; // lazy loaded modules
|
||||||
std::vector<Str> _path; // search path
|
|
||||||
|
|
||||||
PyObject* None;
|
PyObject* None;
|
||||||
PyObject* True;
|
PyObject* True;
|
||||||
@ -547,31 +546,75 @@ public:
|
|||||||
return _all_types[obj->type].obj;
|
return _all_types[obj->type].obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject* py_import(StrName name){
|
struct ImportContext{
|
||||||
|
// 0: normal; 1: __init__.py; 2: relative
|
||||||
|
std::vector<std::pair<StrName, int>> pending;
|
||||||
|
|
||||||
|
struct Temp{
|
||||||
|
VM* vm;
|
||||||
|
StrName name;
|
||||||
|
|
||||||
|
Temp(VM* vm, StrName name, int type): vm(vm), name(name){
|
||||||
|
ImportContext* ctx = &vm->_import_context;
|
||||||
|
for(auto& [k,v]: ctx->pending){
|
||||||
|
if(k == name){
|
||||||
|
vm->_error("ImportError", fmt("circular import ", name.escape()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx->pending.emplace_back(name, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Temp(){
|
||||||
|
ImportContext* ctx = &vm->_import_context;
|
||||||
|
ctx->pending.pop_back();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Temp temp(VM* vm, StrName name, int type){
|
||||||
|
return Temp(vm, name, type);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ImportContext _import_context;
|
||||||
|
|
||||||
|
PyObject* py_import(StrName name, bool relative=false){
|
||||||
|
Str filename;
|
||||||
|
int type;
|
||||||
|
if(relative){
|
||||||
|
ImportContext* ctx = &_import_context;
|
||||||
|
type = 2;
|
||||||
|
for(auto it=ctx->pending.rbegin(); it!=ctx->pending.rend(); ++it){
|
||||||
|
if(it->second == 2) continue;
|
||||||
|
if(it->second == 1){
|
||||||
|
filename = fmt(it->first, kPlatformSep, name, ".py");
|
||||||
|
name = fmt(it->first, '.', name).c_str();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(filename.length() == 0) _error("ImportError", "relative import outside of package");
|
||||||
|
}else{
|
||||||
|
type = 0;
|
||||||
|
filename = fmt(name, ".py");
|
||||||
|
}
|
||||||
PyObject* ext_mod = _modules.try_get(name);
|
PyObject* ext_mod = _modules.try_get(name);
|
||||||
if(ext_mod == nullptr){
|
if(ext_mod == nullptr){
|
||||||
Str source;
|
Str source;
|
||||||
auto it = _lazy_modules.find(name);
|
auto it = _lazy_modules.find(name);
|
||||||
if(it == _lazy_modules.end()){
|
if(it == _lazy_modules.end()){
|
||||||
Bytes b = _read_file_cwd(fmt(name, ".py"));
|
Bytes b = _read_file_cwd(filename);
|
||||||
if(!b) {
|
if(!relative && !b){
|
||||||
for(Str path: _path){
|
filename = fmt(name, kPlatformSep, "__init__.py");
|
||||||
#ifdef _WIN32
|
b = _read_file_cwd(filename);
|
||||||
const char* sep = "\\";
|
if(b) type = 1;
|
||||||
#else
|
|
||||||
const char* sep = "/";
|
|
||||||
#endif
|
|
||||||
b = _read_file_cwd(fmt(path, sep, name, ".py"));
|
|
||||||
if(b) break;
|
|
||||||
}
|
}
|
||||||
if(!b) _error("ImportError", fmt("module ", name.escape(), " not found"));
|
if(!b) _error("ImportError", fmt("module ", name.escape(), " not found"));
|
||||||
}
|
|
||||||
source = Str(b.str());
|
source = Str(b.str());
|
||||||
}else{
|
}else{
|
||||||
source = it->second;
|
source = it->second;
|
||||||
_lazy_modules.erase(it);
|
_lazy_modules.erase(it);
|
||||||
}
|
}
|
||||||
CodeObject_ code = compile(source, Str(name.sv())+".py", EXEC_MODE);
|
auto _ = _import_context.temp(this, name, type);
|
||||||
|
CodeObject_ code = compile(source, filename, EXEC_MODE);
|
||||||
PyObject* new_mod = new_module(name);
|
PyObject* new_mod = new_module(name);
|
||||||
_exec(code, new_mod);
|
_exec(code, new_mod);
|
||||||
new_mod->attr()._try_perfect_rehash();
|
new_mod->attr()._try_perfect_rehash();
|
||||||
|
3
tests/30_import.py
Normal file
3
tests/30_import.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import test
|
||||||
|
|
||||||
|
assert test.add(1, 2) == 13
|
Loading…
x
Reference in New Issue
Block a user