blob: fa668f1da7005921bdfe6641537cd29c35106fe9 [file] [log] [blame]
Jeremy Hylton8b966dc2001-04-09 04:35:35 +00001"""Module symbol-table generator"""
2
3from compiler import ast
Jeremy Hylton364f9b92001-04-12 06:40:42 +00004from compiler.consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL, SC_UNKNOWN
Jeremy Hyltonc59e2202001-08-27 22:56:16 +00005from compiler.misc import mangle
Jeremy Hyltonf870c952001-04-09 13:57:32 +00006import types
Jeremy Hylton8b966dc2001-04-09 04:35:35 +00007
Jeremy Hyltonc59e2202001-08-27 22:56:16 +00008
Jeremy Hylton364f9b92001-04-12 06:40:42 +00009import sys
10
Jeremy Hyltonf870c952001-04-09 13:57:32 +000011MANGLE_LEN = 256
Jeremy Hylton8b966dc2001-04-09 04:35:35 +000012
13class Scope:
14 # XXX how much information do I need about each name?
Jeremy Hyltonf870c952001-04-09 13:57:32 +000015 def __init__(self, name, module, klass=None):
Jeremy Hylton8b966dc2001-04-09 04:35:35 +000016 self.name = name
Jeremy Hyltonf870c952001-04-09 13:57:32 +000017 self.module = module
Jeremy Hylton8b966dc2001-04-09 04:35:35 +000018 self.defs = {}
19 self.uses = {}
20 self.globals = {}
21 self.params = {}
Jeremy Hylton364f9b92001-04-12 06:40:42 +000022 self.frees = {}
23 self.cells = {}
Jeremy Hyltonf870c952001-04-09 13:57:32 +000024 self.children = []
Jeremy Hylton364f9b92001-04-12 06:40:42 +000025 # nested is true if the class could contain free variables,
26 # i.e. if it is nested within another function.
27 self.nested = None
Jeremy Hyltond4be10d2001-08-29 18:10:51 +000028 self.generator = None
Jeremy Hyltonf870c952001-04-09 13:57:32 +000029 self.klass = None
30 if klass is not None:
31 for i in range(len(klass)):
32 if klass[i] != '_':
33 self.klass = klass[i:]
34 break
Jeremy Hylton8b966dc2001-04-09 04:35:35 +000035
36 def __repr__(self):
37 return "<%s: %s>" % (self.__class__.__name__, self.name)
38
Jeremy Hyltonf870c952001-04-09 13:57:32 +000039 def mangle(self, name):
40 if self.klass is None:
41 return name
Jeremy Hyltonc59e2202001-08-27 22:56:16 +000042 return mangle(name, self.klass)
Jeremy Hyltonf870c952001-04-09 13:57:32 +000043
Jeremy Hylton8b966dc2001-04-09 04:35:35 +000044 def add_def(self, name):
Jeremy Hyltonf870c952001-04-09 13:57:32 +000045 self.defs[self.mangle(name)] = 1
Jeremy Hylton8b966dc2001-04-09 04:35:35 +000046
47 def add_use(self, name):
Jeremy Hyltonf870c952001-04-09 13:57:32 +000048 self.uses[self.mangle(name)] = 1
Jeremy Hylton8b966dc2001-04-09 04:35:35 +000049
50 def add_global(self, name):
Jeremy Hyltonf870c952001-04-09 13:57:32 +000051 name = self.mangle(name)
Jeremy Hylton8b966dc2001-04-09 04:35:35 +000052 if self.uses.has_key(name) or self.defs.has_key(name):
53 pass # XXX warn about global following def/use
54 if self.params.has_key(name):
55 raise SyntaxError, "%s in %s is global and parameter" % \
56 (name, self.name)
57 self.globals[name] = 1
Jeremy Hyltonf870c952001-04-09 13:57:32 +000058 self.module.add_def(name)
Jeremy Hylton8b966dc2001-04-09 04:35:35 +000059
60 def add_param(self, name):
Jeremy Hyltonf870c952001-04-09 13:57:32 +000061 name = self.mangle(name)
Jeremy Hylton8b966dc2001-04-09 04:35:35 +000062 self.defs[name] = 1
63 self.params[name] = 1
64
65 def get_names(self):
66 d = {}
67 d.update(self.defs)
68 d.update(self.uses)
Jeremy Hyltondbdb28e2001-04-09 20:11:59 +000069 d.update(self.globals)
Jeremy Hylton8b966dc2001-04-09 04:35:35 +000070 return d.keys()
71
Jeremy Hyltonf870c952001-04-09 13:57:32 +000072 def add_child(self, child):
73 self.children.append(child)
74
75 def get_children(self):
76 return self.children
77
Jeremy Hylton364f9b92001-04-12 06:40:42 +000078 def DEBUG(self):
Jeremy Hylton364f9b92001-04-12 06:40:42 +000079 print >> sys.stderr, self.name, self.nested and "nested" or ""
80 print >> sys.stderr, "\tglobals: ", self.globals
81 print >> sys.stderr, "\tcells: ", self.cells
82 print >> sys.stderr, "\tdefs: ", self.defs
83 print >> sys.stderr, "\tuses: ", self.uses
84 print >> sys.stderr, "\tfrees:", self.frees
85
86 def check_name(self, name):
87 """Return scope of name.
88
89 The scope of a name could be LOCAL, GLOBAL, FREE, or CELL.
90 """
91 if self.globals.has_key(name):
92 return SC_GLOBAL
93 if self.cells.has_key(name):
94 return SC_CELL
95 if self.defs.has_key(name):
96 return SC_LOCAL
97 if self.nested and (self.frees.has_key(name) or
98 self.uses.has_key(name)):
99 return SC_FREE
100 if self.nested:
101 return SC_UNKNOWN
102 else:
103 return SC_GLOBAL
104
105 def get_free_vars(self):
106 if not self.nested:
107 return ()
108 free = {}
109 free.update(self.frees)
110 for name in self.uses.keys():
111 if not (self.defs.has_key(name) or
112 self.globals.has_key(name)):
113 free[name] = 1
114 return free.keys()
115
116 def handle_children(self):
117 for child in self.children:
118 frees = child.get_free_vars()
119 globals = self.add_frees(frees)
120 for name in globals:
121 child.force_global(name)
122
123 def force_global(self, name):
124 """Force name to be global in scope.
125
126 Some child of the current node had a free reference to name.
127 When the child was processed, it was labelled a free
128 variable. Now that all its enclosing scope have been
129 processed, the name is known to be a global or builtin. So
130 walk back down the child chain and set the name to be global
131 rather than free.
132
133 Be careful to stop if a child does not think the name is
Tim Peterse0c446b2001-10-18 21:57:37 +0000134 free.
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000135 """
136 self.globals[name] = 1
137 if self.frees.has_key(name):
138 del self.frees[name]
139 for child in self.children:
140 if child.check_name(name) == SC_FREE:
141 child.force_global(name)
142
143 def add_frees(self, names):
144 """Process list of free vars from nested scope.
145
146 Returns a list of names that are either 1) declared global in the
147 parent or 2) undefined in a top-level parent. In either case,
148 the nested scope should treat them as globals.
149 """
150 child_globals = []
151 for name in names:
152 sc = self.check_name(name)
153 if self.nested:
154 if sc == SC_UNKNOWN or sc == SC_FREE \
155 or isinstance(self, ClassScope):
156 self.frees[name] = 1
157 elif sc == SC_GLOBAL:
158 child_globals.append(name)
159 elif isinstance(self, FunctionScope) and sc == SC_LOCAL:
160 self.cells[name] = 1
Jeremy Hyltoncd8a1272001-08-27 21:06:35 +0000161 elif sc != SC_CELL:
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000162 child_globals.append(name)
163 else:
164 if sc == SC_LOCAL:
165 self.cells[name] = 1
Jeremy Hyltoncd8a1272001-08-27 21:06:35 +0000166 elif sc != SC_CELL:
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000167 child_globals.append(name)
168 return child_globals
169
170 def get_cell_vars(self):
171 return self.cells.keys()
172
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000173class ModuleScope(Scope):
174 __super_init = Scope.__init__
Tim Peterse0c446b2001-10-18 21:57:37 +0000175
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000176 def __init__(self):
Jeremy Hyltonf870c952001-04-09 13:57:32 +0000177 self.__super_init("global", self)
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000178
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000179class FunctionScope(Scope):
180 pass
181
182class LambdaScope(FunctionScope):
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000183 __super_init = Scope.__init__
184
185 __counter = 1
Tim Peterse0c446b2001-10-18 21:57:37 +0000186
Jeremy Hyltonf870c952001-04-09 13:57:32 +0000187 def __init__(self, module, klass=None):
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000188 i = self.__counter
189 self.__counter += 1
Jeremy Hyltonf870c952001-04-09 13:57:32 +0000190 self.__super_init("lambda.%d" % i, module, klass)
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000191
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000192class ClassScope(Scope):
Jeremy Hyltonf870c952001-04-09 13:57:32 +0000193 __super_init = Scope.__init__
194
195 def __init__(self, name, module):
196 self.__super_init(name, module, name)
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000197
198class SymbolVisitor:
199 def __init__(self):
200 self.scopes = {}
Jeremy Hyltonf870c952001-04-09 13:57:32 +0000201 self.klass = None
Tim Peterse0c446b2001-10-18 21:57:37 +0000202
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000203 # node that define new scopes
204
205 def visitModule(self, node):
Jeremy Hyltonf870c952001-04-09 13:57:32 +0000206 scope = self.module = self.scopes[node] = ModuleScope()
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000207 self.visit(node.node, scope)
208
Barry Warsaw52acb492001-12-21 20:04:22 +0000209 visitExpression = visitModule
210
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000211 def visitFunction(self, node, parent):
212 parent.add_def(node.name)
213 for n in node.defaults:
214 self.visit(n, parent)
Jeremy Hyltonf870c952001-04-09 13:57:32 +0000215 scope = FunctionScope(node.name, self.module, self.klass)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000216 if parent.nested or isinstance(parent, FunctionScope):
217 scope.nested = 1
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000218 self.scopes[node] = scope
Jeremy Hyltondbdb28e2001-04-09 20:11:59 +0000219 self._do_args(scope, node.argnames)
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000220 self.visit(node.code, scope)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000221 self.handle_free_vars(scope, parent)
Tim Peterse0c446b2001-10-18 21:57:37 +0000222
Jeremy Hyltonead21f52003-08-28 02:09:26 +0000223 def visitLambda(self, node, parent, assign=0):
224 # Lambda is an expression, so it could appear in an expression
225 # context where assign is passed. The transformer should catch
226 # any code that has a lambda on the left-hand side.
227 assert not assign
228
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000229 for n in node.defaults:
230 self.visit(n, parent)
Jeremy Hyltonf870c952001-04-09 13:57:32 +0000231 scope = LambdaScope(self.module, self.klass)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000232 if parent.nested or isinstance(parent, FunctionScope):
233 scope.nested = 1
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000234 self.scopes[node] = scope
Jeremy Hyltondbdb28e2001-04-09 20:11:59 +0000235 self._do_args(scope, node.argnames)
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000236 self.visit(node.code, scope)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000237 self.handle_free_vars(scope, parent)
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000238
Jeremy Hyltondbdb28e2001-04-09 20:11:59 +0000239 def _do_args(self, scope, args):
240 for name in args:
241 if type(name) == types.TupleType:
242 self._do_args(scope, name)
243 else:
244 scope.add_param(name)
245
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000246 def handle_free_vars(self, scope, parent):
247 parent.add_child(scope)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000248 scope.handle_children()
249
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000250 def visitClass(self, node, parent):
251 parent.add_def(node.name)
252 for n in node.bases:
253 self.visit(n, parent)
Jeremy Hyltonf870c952001-04-09 13:57:32 +0000254 scope = ClassScope(node.name, self.module)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000255 if parent.nested or isinstance(parent, FunctionScope):
256 scope.nested = 1
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000257 if node.doc is not None:
258 scope.add_def('__doc__')
259 scope.add_def('__module__')
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000260 self.scopes[node] = scope
Jeremy Hyltonf870c952001-04-09 13:57:32 +0000261 prev = self.klass
262 self.klass = node.name
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000263 self.visit(node.code, scope)
Jeremy Hyltonf870c952001-04-09 13:57:32 +0000264 self.klass = prev
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000265 self.handle_free_vars(scope, parent)
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000266
267 # name can be a def or a use
268
269 # XXX a few calls and nodes expect a third "assign" arg that is
270 # true if the name is being used as an assignment. only
271 # expressions contained within statements may have the assign arg.
272
273 def visitName(self, node, scope, assign=0):
274 if assign:
275 scope.add_def(node.name)
276 else:
277 scope.add_use(node.name)
278
279 # operations that bind new names
280
281 def visitFor(self, node, scope):
282 self.visit(node.assign, scope, 1)
283 self.visit(node.list, scope)
284 self.visit(node.body, scope)
285 if node.else_:
286 self.visit(node.else_, scope)
287
288 def visitFrom(self, node, scope):
289 for name, asname in node.names:
290 if name == "*":
291 continue
292 scope.add_def(asname or name)
293
294 def visitImport(self, node, scope):
295 for name, asname in node.names:
296 i = name.find(".")
297 if i > -1:
298 name = name[:i]
299 scope.add_def(asname or name)
300
Jeremy Hyltond4be10d2001-08-29 18:10:51 +0000301 def visitGlobal(self, node, scope):
302 for name in node.names:
303 scope.add_global(name)
304
305 def visitAssign(self, node, scope):
306 """Propagate assignment flag down to child nodes.
307
308 The Assign node doesn't itself contains the variables being
309 assigned to. Instead, the children in node.nodes are visited
310 with the assign flag set to true. When the names occur in
311 those nodes, they are marked as defs.
312
313 Some names that occur in an assignment target are not bound by
314 the assignment, e.g. a name occurring inside a slice. The
315 visitor handles these nodes specially; they do not propagate
316 the assign flag to their children.
317 """
318 for n in node.nodes:
319 self.visit(n, scope, 1)
320 self.visit(node.expr, scope)
321
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000322 def visitAssName(self, node, scope, assign=1):
323 scope.add_def(node.name)
324
Jeremy Hyltoncd8a1272001-08-27 21:06:35 +0000325 def visitAssAttr(self, node, scope, assign=0):
326 self.visit(node.expr, scope, 0)
327
328 def visitSubscript(self, node, scope, assign=0):
329 self.visit(node.expr, scope, 0)
330 for n in node.subs:
331 self.visit(n, scope, 0)
Jeremy Hyltond4be10d2001-08-29 18:10:51 +0000332
333 def visitSlice(self, node, scope, assign=0):
Jeremy Hylton652a2242001-09-14 22:45:57 +0000334 self.visit(node.expr, scope, 0)
Jeremy Hyltond4be10d2001-08-29 18:10:51 +0000335 if node.lower:
336 self.visit(node.lower, scope, 0)
337 if node.upper:
338 self.visit(node.upper, scope, 0)
Tim Peterse0c446b2001-10-18 21:57:37 +0000339
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000340 def visitAugAssign(self, node, scope):
Jeremy Hylton5c9aad62001-04-12 07:06:25 +0000341 # If the LHS is a name, then this counts as assignment.
342 # Otherwise, it's just use.
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000343 self.visit(node.node, scope)
Jeremy Hylton5c9aad62001-04-12 07:06:25 +0000344 if isinstance(node.node, ast.Name):
345 self.visit(node.node, scope, 1) # XXX worry about this
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000346 self.visit(node.expr, scope)
347
Jeremy Hyltonf870c952001-04-09 13:57:32 +0000348 # prune if statements if tests are false
349
350 _const_types = types.StringType, types.IntType, types.FloatType
351
352 def visitIf(self, node, scope):
353 for test, body in node.tests:
354 if isinstance(test, ast.Const):
355 if type(test.value) in self._const_types:
356 if not test.value:
357 continue
358 self.visit(test, scope)
359 self.visit(body, scope)
360 if node.else_:
361 self.visit(node.else_, scope)
362
Jeremy Hyltond4be10d2001-08-29 18:10:51 +0000363 # a yield statement signals a generator
364
365 def visitYield(self, node, scope):
Jeremy Hylton652a2242001-09-14 22:45:57 +0000366 scope.generator = 1
Jeremy Hyltond4be10d2001-08-29 18:10:51 +0000367 self.visit(node.value, scope)
368
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000369def sort(l):
370 l = l[:]
371 l.sort()
372 return l
373
374def list_eq(l1, l2):
375 return sort(l1) == sort(l2)
376
377if __name__ == "__main__":
378 import sys
379 from compiler import parseFile, walk
380 import symtable
381
Jeremy Hyltonf870c952001-04-09 13:57:32 +0000382 def get_names(syms):
383 return [s for s in [s.get_name() for s in syms.get_symbols()]
Tim Peterse0c446b2001-10-18 21:57:37 +0000384 if not (s.startswith('_[') or s.startswith('.'))]
385
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000386 for file in sys.argv[1:]:
387 print file
388 f = open(file)
389 buf = f.read()
390 f.close()
391 syms = symtable.symtable(buf, file, "exec")
Jeremy Hyltonf870c952001-04-09 13:57:32 +0000392 mod_names = get_names(syms)
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000393 tree = parseFile(file)
394 s = SymbolVisitor()
395 walk(tree, s)
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000396
Jeremy Hyltonf870c952001-04-09 13:57:32 +0000397 # compare module-level symbols
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000398 names2 = s.scopes[tree].get_names()
Jeremy Hyltonf870c952001-04-09 13:57:32 +0000399
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000400 if not list_eq(mod_names, names2):
Jeremy Hyltonf870c952001-04-09 13:57:32 +0000401 print
Jeremy Hylton8b966dc2001-04-09 04:35:35 +0000402 print "oops", file
403 print sort(mod_names)
404 print sort(names2)
405 sys.exit(-1)
Jeremy Hyltonf870c952001-04-09 13:57:32 +0000406
407 d = {}
408 d.update(s.scopes)
409 del d[tree]
410 scopes = d.values()
411 del d
412
413 for s in syms.get_symbols():
414 if s.is_namespace():
415 l = [sc for sc in scopes
416 if sc.name == s.get_name()]
417 if len(l) > 1:
418 print "skipping", s.get_name()
419 else:
420 if not list_eq(get_names(s.get_namespace()),
421 l[0].get_names()):
422 print s.get_name()
Jeremy Hyltondbdb28e2001-04-09 20:11:59 +0000423 print sort(get_names(s.get_namespace()))
424 print sort(l[0].get_names())
Jeremy Hyltonf870c952001-04-09 13:57:32 +0000425 sys.exit(-1)