Commit c3b3f6a6 authored by Travis Hance's avatar Travis Hance

return globals() as locals() for module-level scopes

parent 2bfcd7d1
...@@ -105,6 +105,8 @@ public: ...@@ -105,6 +105,8 @@ public:
bool isPassedToViaClosure(InternedString name) override { return false; } bool isPassedToViaClosure(InternedString name) override { return false; }
bool areLocalsFromModule() override { return true; }
InternedString mangleName(InternedString id) override { return id; } InternedString mangleName(InternedString id) override { return id; }
InternedString internString(llvm::StringRef s) override { abort(); } InternedString internString(llvm::StringRef s) override { abort(); }
}; };
...@@ -245,6 +247,8 @@ public: ...@@ -245,6 +247,8 @@ public:
return usage->got_from_closure.count(name) > 0 || usage->passthrough_accesses.count(name) > 0; return usage->got_from_closure.count(name) > 0 || usage->passthrough_accesses.count(name) > 0;
} }
bool areLocalsFromModule() override { return false; }
InternedString mangleName(const InternedString id) override { InternedString mangleName(const InternedString id) override {
return pyston::mangleName(id, usage->private_name, usage->scoping->getInternedStrings()); return pyston::mangleName(id, usage->private_name, usage->scoping->getInternedStrings());
} }
......
...@@ -114,6 +114,8 @@ public: ...@@ -114,6 +114,8 @@ public:
// `exec` or `eval` scope. // `exec` or `eval` scope.
virtual bool usesNameLookup() = 0; virtual bool usesNameLookup() = 0;
virtual bool areLocalsFromModule() = 0;
virtual InternedString mangleName(InternedString id) = 0; virtual InternedString mangleName(InternedString id) = 0;
virtual InternedString internString(llvm::StringRef) = 0; virtual InternedString internString(llvm::StringRef) = 0;
}; };
......
...@@ -1095,15 +1095,7 @@ Value ASTInterpreter::visit_name(AST_Name* node) { ...@@ -1095,15 +1095,7 @@ Value ASTInterpreter::visit_name(AST_Name* node) {
return Value(); return Value();
} }
case ScopeInfo::VarScopeType::NAME: { case ScopeInfo::VarScopeType::NAME: {
assert(frame_info.boxedLocals->cls == dict_cls); return boxedLocalsGet(frame_info.boxedLocals, node->id.c_str(), source_info->parent_module);
auto& d = static_cast<BoxedDict*>(frame_info.boxedLocals)->d;
auto it = d.find(boxString(node->id.str()));
if (it != d.end()) {
Box* value = it->second;
return value;
}
return getGlobal(source_info->parent_module, &node->id.str());
} }
default: default:
abort(); abort();
...@@ -1170,7 +1162,6 @@ Box* astInterpretFunctionEval(CompiledFunction* cf, Box* boxedLocals) { ...@@ -1170,7 +1162,6 @@ Box* astInterpretFunctionEval(CompiledFunction* cf, Box* boxedLocals) {
ASTInterpreter interpreter(cf); ASTInterpreter interpreter(cf);
interpreter.initArguments(0, NULL, NULL, NULL, NULL, NULL, NULL); interpreter.initArguments(0, NULL, NULL, NULL, NULL, NULL, NULL);
RELEASE_ASSERT(boxedLocals->cls == dict_cls, "we don't support non-dicts here yet");
interpreter.setBoxedLocals(boxedLocals); interpreter.setBoxedLocals(boxedLocals);
Value v = ASTInterpreter::execute(interpreter); Value v = ASTInterpreter::execute(interpreter);
......
...@@ -638,12 +638,20 @@ Box* fastLocalsToBoxedLocals() { ...@@ -638,12 +638,20 @@ Box* fastLocalsToBoxedLocals() {
for (PythonFrameIterator& frame_iter : unwindPythonFrames()) { for (PythonFrameIterator& frame_iter : unwindPythonFrames()) {
BoxedDict* d; BoxedDict* d;
BoxedClosure* closure; BoxedClosure* closure;
CompiledFunction* cf;
FrameInfo* frame_info; FrameInfo* frame_info;
CompiledFunction* cf = frame_iter.getCF();
ScopeInfo* scope_info = cf->clfunc->source->getScopeInfo();
if (scope_info->areLocalsFromModule()) {
// TODO we should cache this in frame_info->locals or something so that locals()
// (and globals() too) will always return the same dict
return makeAttrWrapper(getCurrentModule());
}
if (frame_iter.getId().type == PythonFrameId::COMPILED) { if (frame_iter.getId().type == PythonFrameId::COMPILED) {
d = new BoxedDict(); d = new BoxedDict();
cf = frame_iter.getCF();
uint64_t ip = frame_iter.getId().ip; uint64_t ip = frame_iter.getId().ip;
assert(ip > cf->code_start); assert(ip > cf->code_start);
...@@ -727,7 +735,6 @@ Box* fastLocalsToBoxedLocals() { ...@@ -727,7 +735,6 @@ Box* fastLocalsToBoxedLocals() {
} else if (frame_iter.getId().type == PythonFrameId::INTERPRETED) { } else if (frame_iter.getId().type == PythonFrameId::INTERPRETED) {
d = localsForInterpretedFrame((void*)frame_iter.getId().bp, true); d = localsForInterpretedFrame((void*)frame_iter.getId().bp, true);
closure = passedClosureForInterpretedFrame((void*)frame_iter.getId().bp); closure = passedClosureForInterpretedFrame((void*)frame_iter.getId().bp);
cf = getCFForInterpretedFrame((void*)frame_iter.getId().bp);
frame_info = getFrameInfoForInterpretedFrame((void*)frame_iter.getId().bp); frame_info = getFrameInfoForInterpretedFrame((void*)frame_iter.getId().bp);
} else { } else {
abort(); abort();
...@@ -747,7 +754,6 @@ Box* fastLocalsToBoxedLocals() { ...@@ -747,7 +754,6 @@ Box* fastLocalsToBoxedLocals() {
const std::string& name = attr_offset.first(); const std::string& name = attr_offset.first();
int offset = attr_offset.second; int offset = attr_offset.second;
Box* val = closure->attrs.attr_list->attrs[offset]; Box* val = closure->attrs.attr_list->attrs[offset];
ScopeInfo* scope_info = cf->clfunc->source->getScopeInfo();
if (val != NULL && scope_info->isPassedToViaClosure(scope_info->internString(name))) { if (val != NULL && scope_info->isPassedToViaClosure(scope_info->internString(name))) {
Box* boxedName = boxString(name); Box* boxedName = boxString(name);
if (d->d.count(boxedName) == 0) { if (d->d.count(boxedName) == 0) {
......
...@@ -4450,21 +4450,35 @@ Box* coerceUnicodeToStr(Box* unicode) { ...@@ -4450,21 +4450,35 @@ Box* coerceUnicodeToStr(Box* unicode) {
return r; return r;
} }
// TODO Make these fast, do inline caches and stuff
extern "C" void boxedLocalsSet(Box* boxedLocals, const char* attr, Box* val) { extern "C" void boxedLocalsSet(Box* boxedLocals, const char* attr, Box* val) {
setitem(boxedLocals, boxString(attr), val); setitem(boxedLocals, boxString(attr), val);
} }
extern "C" Box* boxedLocalsGet(Box* boxedLocals, const char* attr, BoxedModule* parent_module) { extern "C" Box* boxedLocalsGet(Box* boxedLocals, const char* attr, BoxedModule* parent_module) {
assert(parent_module->cls == module_cls); assert(parent_module->cls == module_cls);
assert(boxedLocals != NULL); assert(boxedLocals != NULL);
RELEASE_ASSERT(boxedLocals->cls == dict_cls, "we don't support non-dict here yet");
if (boxedLocals->cls == dict_cls) {
auto& d = static_cast<BoxedDict*>(boxedLocals)->d; auto& d = static_cast<BoxedDict*>(boxedLocals)->d;
auto it = d.find(boxString(attr)); auto it = d.find(boxString(attr));
if (it != d.end()) { if (it != d.end()) {
Box* value = it->second; Box* value = it->second;
return value; return value;
} }
} else {
try {
return getitem(boxedLocals, boxString(attr));
} catch (ExcInfo e) {
// TODO should check the exact semantic here but it's something like:
// If it throws a KeyError, then the variable doesn't exist so move on
// and check the globals (below); otherwise, just propogate the exception.
if (!isInstance(e.value, KeyError)) {
throw;
}
}
}
// TODO exception name? // TODO exception name?
std::string attr_string(attr); std::string attr_string(attr);
......
...@@ -5,17 +5,17 @@ print eval("3 + 4") ...@@ -5,17 +5,17 @@ print eval("3 + 4")
a = 5 a = 5
print eval("a") print eval("a")
#print eval("[b for b in range(5)]") print eval("[b for b in range(5)]")
#print b print b
#c = 2 c = 2
#print eval("[c for c in range(5)]") print eval("[c for c in range(5)]")
#print c print c
#try: try:
# print eval("int('abc')") print eval("int('abc')")
#except ValueError: except ValueError:
# print 'got ValueError' print 'got ValueError'
d = 19 d = 19
e = 20 e = 20
...@@ -85,7 +85,7 @@ o = 300 ...@@ -85,7 +85,7 @@ o = 300
print 'eval eval o', eval("eval('o')") print 'eval eval o', eval("eval('o')")
# This works in the global scope but not in the local scope, because o1 is a global: # This works in the global scope but not in the local scope, because o1 is a global:
#print eval("[(lambda p1 : p1 + o1)(5) for o1 in range(5)]") # print eval("[(lambda p1 : p1 + o1)(5) for o1 in range(5)]")
def lambda_func(): def lambda_func():
try: try:
pass #print eval("[(lambda p2 : p2 + o2)(5) for o2 in range(5)]") pass #print eval("[(lambda p2 : p2 + o2)(5) for o2 in range(5)]")
......
...@@ -18,3 +18,8 @@ except NameError: ...@@ -18,3 +18,8 @@ except NameError:
# You're allowed to assign through globals and have it affect the module: # You're allowed to assign through globals and have it affect the module:
globals()['x'] = 1 globals()['x'] = 1
print x print x
# locals should do the same as globals
print locals()['x']
locals()['x'] = 2
print x
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