| 
									
										
										
										
											2001-03-22 23:32:22 +00:00
										 |  |  | """Interface to the compiler's internal symbol tables""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import _symtable | 
					
						
							|  |  |  | from _symtable import USE, DEF_GLOBAL, DEF_LOCAL, DEF_PARAM, \ | 
					
						
							|  |  |  |      DEF_STAR, DEF_DOUBLESTAR, DEF_INTUPLE, DEF_FREE, \ | 
					
						
							| 
									
										
										
										
											2001-04-16 18:43:18 +00:00
										 |  |  |      DEF_FREE_GLOBAL, DEF_FREE_CLASS, DEF_IMPORT, DEF_BOUND, \ | 
					
						
							|  |  |  |      OPT_IMPORT_STAR, OPT_EXEC, OPT_BARE_EXEC | 
					
						
							| 
									
										
										
										
											2001-03-22 23:32:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | import weakref | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-03-23 15:41:14 +00:00
										 |  |  | __all__ = ["symtable", "SymbolTable", "newSymbolTable", "Class", | 
					
						
							|  |  |  |            "Function", "Symbol"] | 
					
						
							| 
									
										
										
										
											2001-03-22 23:32:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def symtable(code, filename, compile_type): | 
					
						
							|  |  |  |     raw = _symtable.symtable(code, filename, compile_type) | 
					
						
							|  |  |  |     return newSymbolTable(raw[0], filename) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class SymbolTableFactory: | 
					
						
							|  |  |  |     def __init__(self): | 
					
						
							|  |  |  |         self.__memo = weakref.WeakValueDictionary() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def new(self, table, filename): | 
					
						
							|  |  |  |         if table.type == _symtable.TYPE_FUNCTION: | 
					
						
							|  |  |  |             return Function(table, filename) | 
					
						
							|  |  |  |         if table.type == _symtable.TYPE_CLASS: | 
					
						
							|  |  |  |             return Class(table, filename) | 
					
						
							|  |  |  |         return SymbolTable(table, filename) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __call__(self, table, filename): | 
					
						
							|  |  |  |         key = table, filename | 
					
						
							|  |  |  |         obj = self.__memo.get(key, None) | 
					
						
							|  |  |  |         if obj is None: | 
					
						
							|  |  |  |             obj = self.__memo[key] = self.new(table, filename) | 
					
						
							|  |  |  |         return obj | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | newSymbolTable = SymbolTableFactory() | 
					
						
							| 
									
										
										
										
											2001-03-29 04:36:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-03-22 23:32:22 +00:00
										 |  |  | def is_free(flags): | 
					
						
							|  |  |  |     if (flags & (USE | DEF_FREE)) \ | 
					
						
							|  |  |  |        and (flags & (DEF_LOCAL | DEF_PARAM | DEF_GLOBAL)): | 
					
						
							| 
									
										
										
										
											2002-04-04 22:55:58 +00:00
										 |  |  |         return True | 
					
						
							| 
									
										
										
										
											2001-03-22 23:32:22 +00:00
										 |  |  |     if flags & DEF_FREE_CLASS: | 
					
						
							| 
									
										
										
										
											2002-04-04 22:55:58 +00:00
										 |  |  |         return True | 
					
						
							|  |  |  |     return False | 
					
						
							| 
									
										
										
										
											2001-03-22 23:32:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class SymbolTable: | 
					
						
							|  |  |  |     def __init__(self, raw_table, filename): | 
					
						
							|  |  |  |         self._table = raw_table | 
					
						
							|  |  |  |         self._filename = filename | 
					
						
							|  |  |  |         self._symbols = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         if self.__class__ == SymbolTable: | 
					
						
							|  |  |  |             kind = "" | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             kind = "%s " % self.__class__.__name__ | 
					
						
							| 
									
										
										
										
											2001-03-29 04:36:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-03-22 23:32:22 +00:00
										 |  |  |         if self._table.name == "global": | 
					
						
							|  |  |  |             return "<%sSymbolTable for module %s>" % (kind, self._filename) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return "<%sSymbolTable for %s in %s>" % (kind, self._table.name, | 
					
						
							|  |  |  |                                                      self._filename) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_type(self): | 
					
						
							|  |  |  |         if self._table.type == _symtable.TYPE_MODULE: | 
					
						
							|  |  |  |             return "module" | 
					
						
							|  |  |  |         if self._table.type == _symtable.TYPE_FUNCTION: | 
					
						
							|  |  |  |             return "function" | 
					
						
							|  |  |  |         if self._table.type == _symtable.TYPE_CLASS: | 
					
						
							|  |  |  |             return "class" | 
					
						
							|  |  |  |         assert self._table.type in (1, 2, 3), \ | 
					
						
							|  |  |  |                "unexpected type: %s" % self._table.type | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_id(self): | 
					
						
							|  |  |  |         return self._table.id | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_name(self): | 
					
						
							|  |  |  |         return self._table.name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_lineno(self): | 
					
						
							|  |  |  |         return self._table.lineno | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def is_optimized(self): | 
					
						
							|  |  |  |         return bool(self._table.type == _symtable.TYPE_FUNCTION | 
					
						
							|  |  |  |                     and not self._table.optimized) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def is_nested(self): | 
					
						
							|  |  |  |         return bool(self._table.nested) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def has_children(self): | 
					
						
							|  |  |  |         return bool(self._table.children) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def has_exec(self): | 
					
						
							| 
									
										
										
										
											2001-04-16 18:43:18 +00:00
										 |  |  |         """Return true if the scope uses exec""" | 
					
						
							|  |  |  |         return bool(self._table.optimized & (OPT_EXEC | OPT_BARE_EXEC)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def has_import_star(self): | 
					
						
							|  |  |  |         """Return true if the scope uses import *""" | 
					
						
							|  |  |  |         return bool(self._table.optimized & OPT_IMPORT_STAR) | 
					
						
							| 
									
										
										
										
											2001-03-22 23:32:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def get_identifiers(self): | 
					
						
							|  |  |  |         return self._table.symbols.keys() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def lookup(self, name): | 
					
						
							|  |  |  |         sym = self._symbols.get(name) | 
					
						
							|  |  |  |         if sym is None: | 
					
						
							|  |  |  |             flags = self._table.symbols[name] | 
					
						
							|  |  |  |             namespaces = self.__check_children(name) | 
					
						
							|  |  |  |             sym = self._symbols[name] = Symbol(name, flags, namespaces) | 
					
						
							|  |  |  |         return sym | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_symbols(self): | 
					
						
							|  |  |  |         return [self.lookup(ident) for ident in self.get_identifiers()] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __check_children(self, name): | 
					
						
							|  |  |  |         return [newSymbolTable(st, self._filename) | 
					
						
							|  |  |  |                 for st in self._table.children | 
					
						
							|  |  |  |                 if st.name == name] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-03-23 15:41:14 +00:00
										 |  |  |     def get_children(self): | 
					
						
							|  |  |  |         return [newSymbolTable(st, self._filename) | 
					
						
							|  |  |  |                 for st in self._table.children] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-03-22 23:32:22 +00:00
										 |  |  | class Function(SymbolTable): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Default values for instance variables | 
					
						
							|  |  |  |     __params = None | 
					
						
							|  |  |  |     __locals = None | 
					
						
							|  |  |  |     __frees = None | 
					
						
							|  |  |  |     __globals = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __idents_matching(self, test_func): | 
					
						
							|  |  |  |         return tuple([ident for ident in self.get_identifiers() | 
					
						
							|  |  |  |                       if test_func(self._table.symbols[ident])]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_parameters(self): | 
					
						
							|  |  |  |         if self.__params is None: | 
					
						
							|  |  |  |             self.__params = self.__idents_matching(lambda x:x & DEF_PARAM) | 
					
						
							|  |  |  |         return self.__params | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_locals(self): | 
					
						
							|  |  |  |         if self.__locals is None: | 
					
						
							|  |  |  |             self.__locals = self.__idents_matching(lambda x:x & DEF_BOUND) | 
					
						
							|  |  |  |         return self.__locals | 
					
						
							| 
									
										
										
										
											2001-03-29 04:36:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-03-22 23:32:22 +00:00
										 |  |  |     def get_globals(self): | 
					
						
							|  |  |  |         if self.__globals is None: | 
					
						
							|  |  |  |             glob = DEF_GLOBAL | DEF_FREE_GLOBAL | 
					
						
							|  |  |  |             self.__globals = self.__idents_matching(lambda x:x & glob) | 
					
						
							|  |  |  |         return self.__globals | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_frees(self): | 
					
						
							|  |  |  |         if self.__frees is None: | 
					
						
							|  |  |  |             self.__frees = self.__idents_matching(is_free) | 
					
						
							|  |  |  |         return self.__frees | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Class(SymbolTable): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     __methods = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_methods(self): | 
					
						
							|  |  |  |         if self.__methods is None: | 
					
						
							|  |  |  |             d = {} | 
					
						
							|  |  |  |             for st in self._table.children: | 
					
						
							|  |  |  |                 d[st.name] = 1 | 
					
						
							| 
									
										
										
										
											2002-06-02 18:55:56 +00:00
										 |  |  |             self.__methods = tuple(d) | 
					
						
							| 
									
										
										
										
											2001-03-22 23:32:22 +00:00
										 |  |  |         return self.__methods | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Symbol: | 
					
						
							|  |  |  |     def __init__(self, name, flags, namespaces=None): | 
					
						
							|  |  |  |         self.__name = name | 
					
						
							|  |  |  |         self.__flags = flags | 
					
						
							|  |  |  |         self.__namespaces = namespaces or () | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         return "<symbol '%s'>" % self.__name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_name(self): | 
					
						
							|  |  |  |         return self.__name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def is_referenced(self): | 
					
						
							|  |  |  |         return bool(self.__flags & _symtable.USE) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def is_parameter(self): | 
					
						
							|  |  |  |         return bool(self.__flags & DEF_PARAM) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def is_global(self): | 
					
						
							| 
									
										
										
										
											2001-03-29 04:36:09 +00:00
										 |  |  |         return bool((self.__flags & DEF_GLOBAL) | 
					
						
							| 
									
										
										
										
											2001-03-22 23:32:22 +00:00
										 |  |  |                     or (self.__flags & DEF_FREE_GLOBAL)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def is_vararg(self): | 
					
						
							| 
									
										
										
										
											2001-04-16 18:43:18 +00:00
										 |  |  |         return bool(self.__flags & DEF_STAR) | 
					
						
							| 
									
										
										
										
											2001-03-22 23:32:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def is_keywordarg(self): | 
					
						
							| 
									
										
										
										
											2001-04-16 18:43:18 +00:00
										 |  |  |         return bool(self.__flags & DEF_DOUBLESTAR) | 
					
						
							| 
									
										
										
										
											2001-03-22 23:32:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def is_local(self): | 
					
						
							|  |  |  |         return bool(self.__flags & DEF_BOUND) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def is_free(self): | 
					
						
							|  |  |  |         if (self.__flags & (USE | DEF_FREE)) \ | 
					
						
							|  |  |  |             and (self.__flags & (DEF_LOCAL | DEF_PARAM | DEF_GLOBAL)): | 
					
						
							| 
									
										
										
										
											2002-04-04 22:55:58 +00:00
										 |  |  |             return True | 
					
						
							| 
									
										
										
										
											2001-03-22 23:32:22 +00:00
										 |  |  |         if self.__flags & DEF_FREE_CLASS: | 
					
						
							| 
									
										
										
										
											2002-04-04 22:55:58 +00:00
										 |  |  |             return True | 
					
						
							|  |  |  |         return False | 
					
						
							| 
									
										
										
										
											2001-03-22 23:32:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def is_imported(self): | 
					
						
							|  |  |  |         return bool(self.__flags & DEF_IMPORT) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def is_assigned(self): | 
					
						
							|  |  |  |         return bool(self.__flags & DEF_LOCAL) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def is_in_tuple(self): | 
					
						
							|  |  |  |         return bool(self.__flags & DEF_INTUPLE) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def is_namespace(self): | 
					
						
							|  |  |  |         """Returns true if name binding introduces new namespace.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         If the name is used as the target of a function or class | 
					
						
							|  |  |  |         statement, this will be true. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Note that a single name can be bound to multiple objects.  If | 
					
						
							|  |  |  |         is_namespace() is true, the name may also be bound to other | 
					
						
							|  |  |  |         objects, like an int or list, that does not introduce a new | 
					
						
							|  |  |  |         namespace. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         return bool(self.__namespaces) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_namespaces(self): | 
					
						
							|  |  |  |         """Return a list of namespaces bound to this name""" | 
					
						
							|  |  |  |         return self.__namespaces | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_namespace(self): | 
					
						
							|  |  |  |         """Returns the single namespace bound to this name.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Raises ValueError if the name is bound to multiple namespaces. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if len(self.__namespaces) != 1: | 
					
						
							|  |  |  |             raise ValueError, "name is bound to multiple namespaces" | 
					
						
							|  |  |  |         return self.__namespaces[0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == "__main__": | 
					
						
							|  |  |  |     import os, sys | 
					
						
							|  |  |  |     src = open(sys.argv[0]).read() | 
					
						
							|  |  |  |     mod = symtable(src, os.path.split(sys.argv[0])[1], "exec") | 
					
						
							|  |  |  |     for ident in mod.get_identifiers(): | 
					
						
							|  |  |  |         info = mod.lookup(ident) | 
					
						
							|  |  |  |         print info, info.is_local(), info.is_namespace() |