// (C) Copyright 2001 Samuele Pedroni
package org.python.compiler;
import org.python.parser.*;
import org.python.parser.ast.*;
import java.util.*;
public class ScopesCompiler extends Visitor implements ScopeConstants {
private CompilationContext code_compiler;
private Stack scopes;
private ScopeInfo cur = null;
private Hashtable nodeScopes;
private int level = 0;
private int func_level = 0;
public ScopesCompiler(CompilationContext code_compiler, Hashtable nodeScopes) {
this.code_compiler = code_compiler;
this.nodeScopes = nodeScopes;
scopes = new Stack();
}
public void beginScope(String name, int kind, SimpleNode node, ArgListCompiler ac) {
if (cur != null) {
scopes.push(cur);
}
if (kind == FUNCSCOPE)
func_level++;
cur = new ScopeInfo(name, node, level++, kind, func_level, ac);
nodeScopes.put(node, cur);
}
public void endScope() throws Exception {
if (cur.kind == FUNCSCOPE)
func_level--;
level--;
ScopeInfo up = (!scopes.empty()) ? (ScopeInfo) scopes.pop() : null;
//Go into the stack to find a non class containing scope to use making the closure
//See PEP 227
int dist = 1;
ScopeInfo referenceable = up;
for (int i = scopes.size() - 1; i >= 0 && referenceable.kind == CLASSSCOPE; i--, dist++) {
referenceable = ((ScopeInfo) scopes.get(i));
}
cur.cook(referenceable, dist, code_compiler);
cur.dump(); // dbg
cur = up;
}
public void parse(SimpleNode node) throws Exception {
try {
visit(node);
} catch (Throwable t) {
throw org.python.core.parser.fixParseError(null, t, code_compiler.getFilename());
}
}
public Object visitInteractive(Interactive node) throws Exception {
beginScope("<single-top>", TOPSCOPE, node, null);
suite(node.body);
endScope();
return null;
}
public Object visitModule(org.python.parser.ast.Module node) throws Exception {
beginScope("<file-top>", TOPSCOPE, node, null);
suite(node.body);
endScope();
return null;
}
public Object visitExpression(Expression node) throws Exception {
beginScope("<eval-top>", TOPSCOPE, node, null);
visit(new Return(node.body));
endScope();
return null;
}
private void def(String name) {
cur.addBound(name);
}
public Object visitFunctionDef(FunctionDef node) throws Exception {
def(node.name);
ArgListCompiler ac = new ArgListCompiler();
ac.visitArgs(node.args);
exprType[] defaults = ac.getDefaults();
int defc = defaults.length;
for (int i = 0; i < defc; i++) {
visit(defaults[i]);
}
beginScope(node.name, FUNCSCOPE, node, ac);
int n = ac.names.size();
for (int i = 0; i < n; i++) {
cur.addParam((String) ac.names.elementAt(i));
}
for (int i = 0; i < ac.init_code.size(); i++) {
visit((stmtType) ac.init_code.elementAt(i));
}
cur.markFromParam();
suite(node.body);
endScope();
return null;
}
public Object visitLambda(Lambda node) throws Exception {
ArgListCompiler ac = new ArgListCompiler();
ac.visitArgs(node.args);
SimpleNode[] defaults = ac.getDefaults();
int defc = defaults.length;
for (int i = 0; i < defc; i++) {
visit(defaults[i]);
}
beginScope("<lambda>", FUNCSCOPE, node, ac);
int n = ac.names.size();
for (int i = 0; i < n; i++) {
cur.addParam((String) ac.names.elementAt(i));
}
for (int i = 0; i < ac.init_code.size(); i++)
visit((stmtType) ac.init_code.elementAt(i));
cur.markFromParam();
visit(node.body);
endScope();
return null;
}
public void suite(stmtType[] stmts) throws Exception {
int n = stmts.length;
for (int i = 0; i < n; i++)
visit(stmts[i]);
}
public Object visitImport(Import node) throws Exception {
int n = node.names.length;
for (int i = 0; i < n; i++) {
if (node.names[i].asname != null)
cur.addBound(node.names[i].asname);
else {
String name = node.names[i].name;
if (name.indexOf('.') > 0)
name = name.substring(0, name.indexOf('.'));
cur.addBound(name);
}
}
return null;
}
public Object visitImportFrom(ImportFrom node) throws Exception {
Future.checkFromFuture(node); // future stmt support
int n = node.names.length;
if (n == 0) {
cur.from_import_star = true;
return null;
}
for (int i = 0; i < n; i++) {
if (node.names[i].asname != null)
cur.addBound(node.names[i].asname);
else
cur.addBound(node.names[i].name);
}
return null;
}
public Object visitGlobal(Global node) throws Exception {
int n = node.names.length;
for (int i = 0; i < n; i++) {
String name = node.names[i];
int prev = cur.addGlobal(name);
if (prev >= 0) {
if ((prev & FROM_PARAM) != 0)
code_compiler.error("name '" + name + "' is local and global", true, node);
if ((prev & GLOBAL) != 0)
continue;
String what;
if ((prev & BOUND) != 0)
what = "assignment";
else
what = "use";
code_compiler.error("name '" + name + "' declared global after " + what, false, node);
}
}
return null;
}
public Object visitExec(Exec node) throws Exception {
cur.exec = true;
if (node.globals == null && node.locals == null)
cur.unqual_exec = true;
traverse(node);
return null;
}
/*
private static void illassign(SimpleNode node) throws Exception {
String target = "operator";
if (node.id == PythonGrammarTreeConstants.JJTCALL_OP) {
target = "function call";
} else if ((node.id == PythonGrammarTreeConstants.JJTFOR_STMT)) {
target = "list comprehension";
}
throw new ParseException("can't assign to "+target,node);
}
*/
public Object visitClassDef(ClassDef node) throws Exception {
def(node.name);
int n = node.bases.length;
for (int i = 0; i < n; i++)
visit(node.bases[i]);
beginScope(node.name, CLASSSCOPE, node, null);
suite(node.body);
endScope();
return null;
}
public Object visitName(Name node) throws Exception {
String name = node.id;
if (node.ctx != expr_contextType.Load) {
if (name.equals("__debug__"))
code_compiler.error("can not assign to __debug__", true, node);
cur.addBound(name);
} else
cur.addUsed(name);
return null;
}
public Object visitListComp(ListComp node) throws Exception {
String tmp = "_[" + (++cur.list_comprehension_count) + "]";
cur.addBound(tmp);
traverse(node);
return null;
}
public Object visitYield(Yield node) throws Exception {
cur.generator = true;
cur.yield_count++;
traverse(node);
return null;
}
}