Commit e6a6a9a4 authored by Travis Hance's avatar Travis Hance Committed by Travis Hance

made an enum for ScopeInfo

parent 6b935b9b
...@@ -104,6 +104,9 @@ public: ...@@ -104,6 +104,9 @@ public:
} }
bool refersToClosure(InternedString name) override { return false; } bool refersToClosure(InternedString name) override { return false; }
bool saveInClosure(InternedString name) override { return false; } bool saveInClosure(InternedString name) override { return false; }
VarScopeType getScopeTypeOfName(InternedString name) override {
return refersToGlobal(name) ? VarScopeType::GLOBAL : VarScopeType::FAST;
}
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(); }
...@@ -174,10 +177,11 @@ private: ...@@ -174,10 +177,11 @@ private:
ScopeInfo* parent; ScopeInfo* parent;
ScopingAnalysis::ScopeNameUsage* usage; ScopingAnalysis::ScopeNameUsage* usage;
AST* ast; AST* ast;
bool usesNameLookup;
public: public:
ScopeInfoBase(ScopeInfo* parent, ScopingAnalysis::ScopeNameUsage* usage, AST* ast) ScopeInfoBase(ScopeInfo* parent, ScopingAnalysis::ScopeNameUsage* usage, AST* ast, bool usesNameLookup)
: parent(parent), usage(usage), ast(ast) { : parent(parent), usage(usage), ast(ast), usesNameLookup(usesNameLookup) {
assert(parent); assert(parent);
assert(usage); assert(usage);
assert(ast); assert(ast);
...@@ -219,6 +223,18 @@ public: ...@@ -219,6 +223,18 @@ public:
return usage->referenced_from_nested.count(name) != 0; return usage->referenced_from_nested.count(name) != 0;
} }
VarScopeType getScopeTypeOfName(InternedString name) override {
if (refersToGlobal(name))
return VarScopeType::GLOBAL;
if (refersToClosure(name))
return VarScopeType::DEREF;
if (usesNameLookup)
return VarScopeType::NAME;
if (saveInClosure(name))
return VarScopeType::CLOSURE;
return VarScopeType::FAST;
}
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());
} }
...@@ -530,15 +546,17 @@ void ScopingAnalysis::processNameUsages(ScopingAnalysis::NameUsageMap* usages) { ...@@ -530,15 +546,17 @@ void ScopingAnalysis::processNameUsages(ScopingAnalysis::NameUsageMap* usages) {
ScopeInfo* parent_info = this->scopes[(usage->parent == NULL) ? this->parent_module : usage->parent->node]; ScopeInfo* parent_info = this->scopes[(usage->parent == NULL) ? this->parent_module : usage->parent->node];
switch (node->type) { switch (node->type) {
case AST_TYPE::ClassDef: case AST_TYPE::ClassDef: {
case AST_TYPE::FunctionDef: ScopeInfoBase* scopeInfo
case AST_TYPE::Lambda: { = new ScopeInfoBase(parent_info, usage, usage->node, true /* usesNameLookup */);
ScopeInfoBase* scopeInfo = new ScopeInfoBase(parent_info, usage, usage->node);
this->scopes[node] = scopeInfo; this->scopes[node] = scopeInfo;
break; break;
} }
case AST_TYPE::FunctionDef:
case AST_TYPE::Lambda:
case AST_TYPE::GeneratorExp: { case AST_TYPE::GeneratorExp: {
ScopeInfoBase* scopeInfo = new ScopeInfoBase(parent_info, usage, usage->node); ScopeInfoBase* scopeInfo
= new ScopeInfoBase(parent_info, usage, usage->node, false /* usesNameLookup */);
this->scopes[node] = scopeInfo; this->scopes[node] = scopeInfo;
break; break;
} }
......
...@@ -33,9 +33,39 @@ public: ...@@ -33,9 +33,39 @@ public:
virtual bool takesClosure() = 0; virtual bool takesClosure() = 0;
virtual bool passesThroughClosure() = 0; virtual bool passesThroughClosure() = 0;
// Various ways a variable name can be resolved.
// These all correspond to STORE_* or LOAD_* bytecodes in CPython.
//
// By way of example:
//
// def f():
// print a # GLOBAL
//
// b = 0
// print b # FAST
//
// c = 0 # CLOSURE
// def g():
// print c # DEREF
//
// class C(object):
// print d # NAME
//
// def g():
// exec "sdfasdfds()"
// # existence of 'exec' statement forces this to NAME:
// print e # NAME
//
// # protip: you can figure this stuff out by doing something like this in CPython:
// import dis
// print dis.dis(g)
enum class VarScopeType { FAST, GLOBAL, CLOSURE, DEREF, NAME };
virtual bool refersToGlobal(InternedString name) = 0; virtual bool refersToGlobal(InternedString name) = 0;
virtual bool refersToClosure(InternedString name) = 0; virtual bool refersToClosure(InternedString name) = 0;
virtual bool saveInClosure(InternedString name) = 0; virtual bool saveInClosure(InternedString name) = 0;
virtual VarScopeType getScopeTypeOfName(InternedString name) = 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;
......
...@@ -999,14 +999,15 @@ Value ASTInterpreter::visit_str(AST_Str* node) { ...@@ -999,14 +999,15 @@ Value ASTInterpreter::visit_str(AST_Str* node) {
Value ASTInterpreter::visit_name(AST_Name* node) { Value ASTInterpreter::visit_name(AST_Name* node) {
switch (node->lookup_type) { switch (node->lookup_type) {
case AST_Name::UNKNOWN: { case AST_Name::UNKNOWN: {
if (scope_info->refersToGlobal(node->id)) { ScopeInfo::VarScopeType vst = scope_info->getScopeTypeOfName(node->id);
if (vst == ScopeInfo::VarScopeType::GLOBAL) {
node->lookup_type = AST_Name::GLOBAL; node->lookup_type = AST_Name::GLOBAL;
return getGlobal(source_info->parent_module, &node->id.str()); return getGlobal(source_info->parent_module, &node->id.str());
} else if (scope_info->refersToClosure(node->id)) { } else if (vst == ScopeInfo::VarScopeType::DEREF) {
node->lookup_type = AST_Name::CLOSURE; node->lookup_type = AST_Name::CLOSURE;
return getattr(passed_closure, node->id.c_str()); return getattr(passed_closure, node->id.c_str());
} else { } else {
bool is_old_local = (source_info->ast->type == AST_TYPE::ClassDef); bool is_old_local = (vst == ScopeInfo::VarScopeType::NAME);
node->lookup_type = is_old_local ? AST_Name::LOCAL : AST_Name::FAST_LOCAL; node->lookup_type = is_old_local ? AST_Name::LOCAL : AST_Name::FAST_LOCAL;
SymMap::iterator it = sym_table.find(node->id); SymMap::iterator it = sym_table.find(node->id);
...@@ -1015,8 +1016,8 @@ Value ASTInterpreter::visit_name(AST_Name* node) { ...@@ -1015,8 +1016,8 @@ Value ASTInterpreter::visit_name(AST_Name* node) {
return value; return value;
} }
// classdefs have different scoping rules than functions: // classdefs (and some other cases like eval) have different scoping rules than functions:
if (source_info->ast->type == AST_TYPE::ClassDef) if (is_old_local)
return getGlobal(source_info->parent_module, &node->id.str()); return getGlobal(source_info->parent_module, &node->id.str());
assertNameDefined(0, node->id.c_str(), UnboundLocalError, true); assertNameDefined(0, node->id.c_str(), UnboundLocalError, true);
......
...@@ -300,6 +300,20 @@ void compileAndRunModule(AST_Module* m, BoxedModule* bm) { ...@@ -300,6 +300,20 @@ void compileAndRunModule(AST_Module* m, BoxedModule* bm) {
((void (*)())cf->code)(); ((void (*)())cf->code)();
} }
/*
void compileAndRunExpression(AST_expr* expr, BoxedModule* bm) {
CompiledFunction* cf;
AST_stmt* stmt = new AST_Expr(expr);
{ // scope for limiting the locked region:
LOCK_REGION(codegen_rwlock.asWrite());
Timer _t("for compileModule()");
ScopingAnalysis* scoping = runScopingAnalysis(
}
*/
// If a function version keeps failing its speculations, kill it (remove it // If a function version keeps failing its speculations, kill it (remove it
// from the list of valid function versions). The next time we go to call // from the list of valid function versions). The next time we go to call
// the function, we will have to pick a different version, potentially recompiling. // the function, we will have to pick a different version, potentially recompiling.
......
...@@ -867,10 +867,11 @@ private: ...@@ -867,10 +867,11 @@ private:
bool is_kill = irstate->getSourceInfo()->liveness->isKill(node, myblock); bool is_kill = irstate->getSourceInfo()->liveness->isKill(node, myblock);
assert(!is_kill || node->id.str()[0] == '#'); assert(!is_kill || node->id.str()[0] == '#');
if (scope_info->refersToGlobal(node->id)) { ScopeInfo::VarScopeType vst = scope_info->getScopeTypeOfName(node->id);
if (vst == ScopeInfo::VarScopeType::GLOBAL) {
assert(!is_kill); assert(!is_kill);
return _getGlobal(node, unw_info); return _getGlobal(node, unw_info);
} else if (scope_info->refersToClosure(node->id)) { } else if (vst == ScopeInfo::VarScopeType::DEREF) {
assert(!is_kill); assert(!is_kill);
assert(scope_info->takesClosure()); assert(scope_info->takesClosure());
...@@ -881,7 +882,7 @@ private: ...@@ -881,7 +882,7 @@ private:
} else { } else {
if (symbol_table.find(node->id) == symbol_table.end()) { if (symbol_table.find(node->id) == symbol_table.end()) {
// classdefs have different scoping rules than functions: // classdefs have different scoping rules than functions:
if (irstate->getSourceInfo()->ast->type == AST_TYPE::ClassDef) { if (vst == ScopeInfo::VarScopeType::NAME) {
return _getGlobal(node, unw_info); return _getGlobal(node, unw_info);
} }
...@@ -900,8 +901,7 @@ private: ...@@ -900,8 +901,7 @@ private:
= static_cast<ConcreteCompilerVariable*>(_getFake(defined_name, true)); = static_cast<ConcreteCompilerVariable*>(_getFake(defined_name, true));
if (is_defined_var) { if (is_defined_var) {
// classdefs have different scoping rules than functions: if (vst == ScopeInfo::VarScopeType::NAME) {
if (irstate->getSourceInfo()->ast->type == AST_TYPE::ClassDef) {
llvm::Value* v = handlePotentiallyUndefined( llvm::Value* v = handlePotentiallyUndefined(
is_defined_var, g.llvm_value_type_ptr, curblock, emitter, false, is_defined_var, g.llvm_value_type_ptr, curblock, emitter, false,
[=](IREmitter& emitter) { [=](IREmitter& emitter) {
......
# expected: fail # expected: fail
# - eval not implemented # - eval not implemented
# - closures not implemented # - closures not implemented
print eval("3 + 4")
a = 5
print eval("a")
print eval("[b for b in range(5)]")
print b
c = 2
print eval("[c for c in range(5)]")
print c
try:
print eval("int('abc')")
except ValueError:
print 'got ValueError'
d = 19
e = 20
i = 21
def func():
print eval("d")
e = 20
print eval("e")
eval("[f for f in range(5)]")
eval("[g for g in range(5)]")
try:
g
except NameError:
print 'g not found'
h = 2
eval("[h for h in range(5)]")
print h
eval("[i for i in range(5)]")
j = 24
def inner():
return j
print eval("inner()")
func()
print i
print eval("(lambda k : k+2)(3)")
l = 100
print eval("(lambda k : l+2)(3)")
print eval("(lambda k : [m for m in range(5)])(3)")
try:
print m
except NameError:
print 'm not found'
n = 200
print eval("(lambda k : [n for n in range(5)])(3)")
print n
print eval("eval('3 + 2342')")
x = 2 x = 2
def wrap(): def wrap():
x = 1 x = 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