001: // (C) Copyright 2001 Samuele Pedroni
002:
003: package org.python.compiler;
004:
005: import java.util.*;
006: import org.python.parser.SimpleNode;
007:
008: public class ScopeInfo extends Object implements ScopeConstants {
009:
010: public SimpleNode scope_node;
011: public String scope_name;
012: public int level;
013: public int func_level;
014: public int list_comprehension_count;
015:
016: public void dump() { // for debugging
017: if (org.python.core.Options.verbose < org.python.core.Py.DEBUG)
018: return;
019: for (int i = 0; i < level; i++)
020: System.err.print(' ');
021: System.err.print(((kind != CLASSSCOPE) ? scope_name : "class "
022: + scope_name)
023: + ": ");
024: for (Enumeration e = tbl.keys(); e.hasMoreElements();) {
025: String name = (String) e.nextElement();
026: SymInfo info = (SymInfo) tbl.get(name);
027: int flags = info.flags;
028: System.err.print(name);
029: if ((flags & BOUND) != 0)
030: System.err.print('=');
031: // func scope global (affect nested scopes)
032: // vs. class scope global
033: if ((flags & NGLOBAL) != 0)
034: System.err.print('G');
035: else if ((flags & CLASS_GLOBAL) != 0)
036: System.err.print('g');
037: if ((flags & PARAM) != 0)
038: System.err.print('P');
039: else if ((flags & FROM_PARAM) != 0)
040: System.err.print('p');
041: if ((flags & CELL) != 0)
042: System.err.print('!');
043: if ((flags & FREE) != 0)
044: System.err.print(",f");
045: System.err.print(" ");
046: }
047: System.err.println();
048: }
049:
050: public ScopeInfo(String name, SimpleNode node, int level, int kind,
051: int func_level, ArgListCompiler ac) {
052: scope_name = name;
053: scope_node = node;
054: this .level = level;
055: this .kind = kind;
056: this .func_level = func_level;
057: this .ac = ac;
058: }
059:
060: public int kind;
061:
062: public boolean unqual_exec;
063: public boolean exec;
064: public boolean from_import_star;
065: public boolean generator;
066: public int yield_count;
067:
068: public ArgListCompiler ac;
069:
070: public Hashtable tbl = new Hashtable();
071: public Vector names = new Vector();
072:
073: public int addGlobal(String name) {
074: // global kind = func vs. class
075: int global = kind == CLASSSCOPE ? CLASS_GLOBAL : NGLOBAL;
076: SymInfo info = (SymInfo) tbl.get(name);
077: if (info == null) {
078: tbl.put(name, new SymInfo(global | BOUND));
079: return -1;
080: }
081: int prev = info.flags;
082: info.flags |= global | BOUND;
083: return prev;
084: }
085:
086: public int local = 0;
087:
088: public void addParam(String name) {
089: //System.out.println("addParam " + name);
090: tbl.put(name, new SymInfo(PARAM | BOUND, local++));
091: names.addElement(name);
092: }
093:
094: public void markFromParam() {
095: for (Enumeration e = tbl.elements(); e.hasMoreElements();) {
096: SymInfo info = (SymInfo) e.nextElement();
097: info.flags |= FROM_PARAM;
098: }
099: }
100:
101: public void addBound(String name) {
102: SymInfo info = (SymInfo) tbl.get(name);
103: if (info == null) {
104: tbl.put(name, new SymInfo(BOUND));
105: return;
106: }
107: info.flags |= BOUND;
108: }
109:
110: public void addUsed(String name) {
111: if (tbl.get(name) == null) {
112: tbl.put(name, new SymInfo(0));
113: return;
114: }
115: }
116:
117: private final static Object PRESENT = new Object();
118:
119: public Hashtable inner_free = new Hashtable();
120:
121: public Vector cellvars = new Vector();
122:
123: public Vector jy_paramcells = new Vector();
124:
125: public int jy_npurecell;
126:
127: public int cell, distance;
128:
129: public ScopeInfo up;
130:
131: //Resolve the names used in the given scope, and mark any freevars used in the up scope
132: public void cook(ScopeInfo up, int distance, CompilationContext ctxt)
133: throws Exception {
134: if (up == null)
135: return; // top level => nop
136: this .up = up;
137: this .distance = distance;
138: boolean func = kind == FUNCSCOPE;
139: Vector purecells = new Vector();
140: cell = 0;
141: boolean some_inner_free = inner_free.size() > 0;
142:
143: for (Enumeration e = inner_free.keys(); e.hasMoreElements();) {
144: String name = (String) e.nextElement();
145: SymInfo info = (SymInfo) tbl.get(name);
146: if (info == null) {
147: tbl.put(name, new SymInfo(FREE));
148: continue;
149: }
150: int flags = info.flags;
151: if (func) {
152: // not func global and bound ?
153: if ((flags & NGLOBAL) == 0 && (flags & BOUND) != 0) {
154: info.flags |= CELL;
155: if ((info.flags & PARAM) != 0)
156: jy_paramcells.addElement(name);
157: cellvars.addElement(name);
158: info.env_index = cell++;
159: if ((flags & PARAM) == 0)
160: purecells.addElement(name);
161: continue;
162: }
163: } else {
164: info.flags |= FREE;
165: }
166: }
167: boolean some_free = false;
168:
169: boolean nested = up.kind != TOPSCOPE;
170: for (Enumeration e = tbl.keys(); e.hasMoreElements();) {
171: String name = (String) e.nextElement();
172: SymInfo info = (SymInfo) tbl.get(name);
173: int flags = info.flags;
174: if (nested && (flags & FREE) != 0)
175: up.inner_free.put(name, PRESENT);
176: if ((flags & (GLOBAL | PARAM | CELL)) == 0) {
177: if ((flags & BOUND) != 0) { // ?? only func
178: // System.err.println("local: "+name);
179: names.addElement(name);
180: info.locals_index = local++;
181: continue;
182: }
183: info.flags |= FREE;
184: some_free = true;
185: if (nested)
186: up.inner_free.put(name, PRESENT);
187: }
188: }
189: if ((jy_npurecell = purecells.size()) > 0) {
190: int sz = purecells.size();
191: for (int i = 0; i < sz; i++) {
192: names.addElement(purecells.elementAt(i));
193: }
194: }
195: if ((unqual_exec || from_import_star)) {
196: if (some_inner_free)
197: dynastuff_trouble(true, ctxt);
198: else if (func_level > 1 && some_free)
199: dynastuff_trouble(false, ctxt);
200: }
201:
202: }
203:
204: private void dynastuff_trouble(boolean inner_free,
205: CompilationContext ctxt) throws Exception {
206: String illegal;
207: if (unqual_exec && from_import_star)
208: illegal = "function '"
209: + scope_name
210: + "' uses import * and bare exec, which are illegal";
211: else if (unqual_exec)
212: illegal = "unqualified exec is not allowed in function '"
213: + scope_name + "'";
214: else
215: illegal = "import * is not allowed in function '"
216: + scope_name + "'";
217: String why;
218: if (inner_free)
219: why = " because it contains a function with free variables";
220: else
221: why = " because it contains free variables";
222: ctxt.error(illegal + why, true, scope_node);
223: }
224:
225: public Vector freevars = new Vector();
226:
227: /**
228: * setup the closure on this scope using the scope passed into cook as up as
229: * the containing scope
230: */
231: public void setup_closure() {
232: setup_closure(up);
233: }
234:
235: /**
236: * setup the closure on this scope using the passed in scope. This is used
237: * by jythonc to setup its closures.
238: */
239: public void setup_closure(ScopeInfo up) {
240: int free = cell; // env = cell...,free...
241: Hashtable up_tbl = up.tbl;
242: boolean nested = up.kind != TOPSCOPE;
243: for (Enumeration e = tbl.keys(); e.hasMoreElements();) {
244: String name = (String) e.nextElement();
245: SymInfo info = (SymInfo) tbl.get(name);
246: int flags = info.flags;
247: if ((flags & FREE) != 0) {
248: SymInfo up_info = (SymInfo) up_tbl.get(name);
249: // ?? differs from CPython -- what is the intended behaviour?
250: if (up_info != null) {
251: int up_flags = up_info.flags;
252: if ((up_flags & (CELL | FREE)) != 0) {
253: info.env_index = free++;
254: freevars.addElement(name);
255: continue;
256: }
257: // ! func global affect nested scopes
258: if (nested && (up_flags & NGLOBAL) != 0) {
259: info.flags = NGLOBAL | BOUND;
260: continue;
261: }
262: }
263: info.flags &= ~FREE;
264: }
265: }
266:
267: }
268:
269: public String toString() {
270: return "ScopeInfo[" + scope_name + " " + kind + "]@"
271: + System.identityHashCode(this);
272: }
273: }
|