Commit 3dfe6311 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Import-related improvements

- Set the import "level" appropriately (takes absolute_import flag into account)
- Add a basic implementation of the __import__() function
- Fix a bug in existing import behavior (would not check sys.modules in certain
  cases)
parent 7fa55eba
......@@ -65,6 +65,7 @@ static AST_Name* makeName(const std::string& id, AST_TYPE::AST_TYPE ctx_type, in
class CFGVisitor : public ASTVisitor {
private:
AST_TYPE::AST_TYPE root_type;
FutureFlags future_flags;
CFG* cfg;
CFGBlock* curblock;
ScopingAnalysis* scoping_analysis;
......@@ -996,8 +997,8 @@ private:
}
public:
CFGVisitor(AST_TYPE::AST_TYPE root_type, ScopingAnalysis* scoping_analysis, CFG* cfg)
: root_type(root_type), cfg(cfg), scoping_analysis(scoping_analysis) {
CFGVisitor(AST_TYPE::AST_TYPE root_type, FutureFlags future_flags, ScopingAnalysis* scoping_analysis, CFG* cfg)
: root_type(root_type), future_flags(future_flags), cfg(cfg), scoping_analysis(scoping_analysis) {
curblock = cfg->addBlock();
curblock->info = "entry";
}
......@@ -1194,7 +1195,15 @@ public:
import->args.push_back(new AST_Num());
static_cast<AST_Num*>(import->args[0])->num_type = AST_Num::INT;
static_cast<AST_Num*>(import->args[0])->n_int = node->level;
// I don't quite understand this but this is what CPython does:
int level;
if (node->level == 0 && !(future_flags & FF_ABSOLUTE_IMPORT))
level = -1;
else
level = node->level;
static_cast<AST_Num*>(import->args[0])->n_int = level;
import->args.push_back(new AST_Tuple());
static_cast<AST_Tuple*>(import->args[1])->ctx_type = AST_TYPE::Load;
for (int i = 0; i < node->names.size(); i++) {
......@@ -2019,7 +2028,7 @@ CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body) {
ScopingAnalysis* scoping_analysis = source->scoping;
CFGVisitor visitor(source->ast->type, scoping_analysis, rtn);
CFGVisitor visitor(source->ast->type, source->parent_module->future_flags, scoping_analysis, rtn);
bool skip_first = false;
......
......@@ -27,6 +27,7 @@
#include "core/types.h"
#include "gc/collector.h"
#include "runtime/ics.h"
#include "runtime/import.h"
#include "runtime/inline/xrange.h"
#include "runtime/list.h"
#include "runtime/long.h"
......@@ -345,6 +346,14 @@ Box* issubclass_func(Box* child, Box* parent) {
return boxBool(isSubclass(static_cast<BoxedClass*>(child), static_cast<BoxedClass*>(parent)));
}
Box* bltinImport(Box* arg) {
if (arg->cls != str_cls) {
raiseExcHelper(TypeError, "__import__() argument 1 must be string, not %s", getTypeName(arg)->c_str());
}
return import(-1, new BoxedTuple({}), &static_cast<BoxedString*>(arg)->s);
}
Box* getattrFunc(Box* obj, Box* _str, Box* default_value) {
if (_str->cls != str_cls) {
raiseExcHelper(TypeError, "getattr(): attribute name must be string");
......@@ -805,6 +814,7 @@ void setupBuiltins() {
Box* issubclass_obj = new BoxedFunction(boxRTFunction((void*)issubclass_func, BOXED_BOOL, 2));
builtins_module->giveAttr("issubclass", issubclass_obj);
builtins_module->giveAttr("__import__", new BoxedFunction(boxRTFunction((void*)bltinImport, UNKNOWN, 1)));
enumerate_cls
= new BoxedHeapClass(type_cls, object_cls, &BoxedEnumerate::gcHandler, 0, sizeof(BoxedEnumerate), false);
......
......@@ -106,6 +106,11 @@ static BoxedModule* importFile(const std::string& name, const std::string& full_
}
static Box* importSub(const std::string& name, const std::string& full_name, Box* parent_module) {
Box* boxed_name = boxStringPtr(&full_name);
BoxedDict* sys_modules = getSysModulesDict();
if (sys_modules->d.find(boxed_name) != sys_modules->d.end())
return sys_modules->d[boxed_name];
BoxedList* path_list;
if (parent_module == NULL) {
path_list = getSysPath();
......@@ -172,15 +177,10 @@ static Box* import(const std::string* name, bool return_first) {
}
std::string prefix_name = std::string(*name, 0, r);
Box* s = boxStringPtr(&prefix_name);
if (sys_modules->d.find(s) != sys_modules->d.end()) {
last_module = sys_modules->d[s];
} else {
std::string small_name = std::string(*name, l, r - l);
last_module = importSub(small_name, prefix_name, last_module);
if (!last_module)
raiseExcHelper(ImportError, "No module named %s", small_name.c_str());
}
std::string small_name = std::string(*name, l, r - l);
last_module = importSub(small_name, prefix_name, last_module);
if (!last_module)
raiseExcHelper(ImportError, "No module named %s", small_name.c_str());
if (l == 0) {
first_module = last_module;
......@@ -225,6 +225,8 @@ static void ensure_fromlist(Box* module, Box* fromlist, const std::string& modul
}
extern "C" Box* import(int level, Box* from_imports, const std::string* module_name) {
RELEASE_ASSERT(level == -1, "");
Box* module = import(module_name, from_imports == None);
assert(module);
......
......@@ -981,7 +981,7 @@ BoxedModule* createModule(const std::string& name, const std::string& fn) {
BoxedDict* d = getSysModulesDict();
Box* b_name = boxStringPtr(&name);
assert(d->d.count(b_name) == 0);
ASSERT(d->d.count(b_name) == 0, "%s", name.c_str());
d->d[b_name] = module;
module->giveAttr("__doc__", None);
......
......@@ -27,3 +27,5 @@ print import_nested_target.y
print z
print y
print __name__
print __import__("import_target") is import_target
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment