Commit d3e045a0 authored by Travis Hance's avatar Travis Hance

treat exec and eval code as top-level scopes (rather than like function...

treat exec and eval code as top-level scopes (rather than like function scopes) in order to get the scope types right
parent c3b3f6a6
......@@ -111,14 +111,74 @@ public:
InternedString internString(llvm::StringRef s) override { abort(); }
};
typedef llvm::DenseSet<InternedString> StrSet;
// Handles the scope in eval or exec
// For example for exec, if you write
// exec "global a ; print a ; print b"
// It will give `a` the GLOBAL scope type and `b` the NAME type.
// (For eval, you can't have global statements, so it will just
// mark everything NAME.)
class EvalExprScopeInfo : public ScopeInfo {
private:
StrSet forced_globals;
struct GlobalStmtVisitor : NoopASTVisitor {
StrSet& result;
GlobalStmtVisitor(StrSet& result) : result(result) {}
bool visit_functiondef(AST_FunctionDef*) override { return true; }
bool visit_classdef(AST_ClassDef*) override { return true; }
bool visit_global(AST_Global* global_stmt) override {
for (InternedString name : global_stmt->names) {
result.insert(name);
}
return true;
}
};
public:
EvalExprScopeInfo() {}
EvalExprScopeInfo(AST* node) {
// Find all the global statements in the node's scope (not delving into FuncitonDefs
// or ClassDefs) and put the names in `forced_globals`.
GlobalStmtVisitor visitor(forced_globals);
node->accept(&visitor);
}
ScopeInfo* getParent() override { return NULL; }
bool createsClosure() override { return false; }
bool takesClosure() override { return false; }
bool passesThroughClosure() override { return false; }
VarScopeType getScopeTypeOfName(InternedString name) override {
if (isCompilerCreatedName(name))
return VarScopeType::FAST;
else if (forced_globals.find(name) != forced_globals.end())
return VarScopeType::GLOBAL;
else
return VarScopeType::NAME;
}
bool usesNameLookup() override { return true; }
bool isPassedToViaClosure(InternedString name) override { return false; }
bool areLocalsFromModule() override { return false; }
InternedString mangleName(InternedString id) override { return id; }
InternedString internString(llvm::StringRef s) override { abort(); }
};
struct ScopingAnalysis::ScopeNameUsage {
AST* node;
ScopeNameUsage* parent;
const std::string* private_name;
ScopingAnalysis* scoping;
typedef llvm::DenseSet<InternedString> StrSet;
// Properties determined from crawling the scope:
StrSet read;
StrSet written;
......@@ -648,8 +708,6 @@ void ScopingAnalysis::processNameUsages(ScopingAnalysis::NameUsageMap* usages) {
ScopeInfo* parent_info = this->scopes[(usage->parent == NULL) ? this->parent_module : usage->parent->node];
switch (node->type) {
case AST_TYPE::Expression:
case AST_TYPE::Suite:
case AST_TYPE::ClassDef: {
ScopeInfoBase* scopeInfo
= new ScopeInfoBase(parent_info, usage, usage->node, true /* usesNameLookup */);
......@@ -723,12 +781,11 @@ ScopingAnalysis::ScopingAnalysis(AST_Module* m) : parent_module(m), interned_str
}
ScopingAnalysis::ScopingAnalysis(AST_Expression* e) : interned_strings(*e->interned_strings.get()) {
auto scope_info = getScopeInfoForNode(e);
scopes[e] = scope_info;
// It's an expression, so it can't have a `global` statement
scopes[e] = new EvalExprScopeInfo();
}
ScopingAnalysis::ScopingAnalysis(AST_Suite* s) : interned_strings(*s->interned_strings.get()) {
auto scope_info = getScopeInfoForNode(s);
scopes[s] = scope_info;
scopes[s] = new EvalExprScopeInfo(s);
}
}
# TODO lots of eval functionality not implemented
print eval("3 + 4")
a = 5
......@@ -85,10 +83,10 @@ o = 300
print 'eval eval o', eval("eval('o')")
# 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():
try:
pass #print eval("[(lambda p2 : p2 + o2)(5) for o2 in range(5)]")
print eval("[(lambda p2 : p2 + o2)(5) for o2 in range(5)]")
except NameError as e:
print e.message
lambda_func()
......@@ -106,9 +104,9 @@ def func2():
print 'shadow3', eval("shadow3 + sum([2 for shadow3 in range(5)]) + shadow3")
func2()
#print 'shadow1', shadow2
#print 'shadow2', shadow2
#print 'shadow3', shadow3
print 'shadow1', shadow2
print 'shadow2', shadow2
print 'shadow3', shadow3
def func3():
......@@ -123,16 +121,12 @@ def func3():
print 'NameError', e.message
func3()
"""
changing_global = -1
def print_changing_global():
print 'changing_global is', changing_global
return 0
eval("[print_changing_global() for changing_global in range(5)]")
"""
def do_changing_local():
# this won't get modified:
changing_local = -1
......
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