0001 """Interface to the compiler's internal symbol tables""" 0002 0003 import _symtable 0004 from _symtable import USE, DEF_GLOBAL, DEF_LOCAL, DEF_PARAM, \ 0005 DEF_STAR, DEF_DOUBLESTAR, DEF_INTUPLE, DEF_FREE, \ 0006 DEF_FREE_GLOBAL, DEF_FREE_CLASS, DEF_IMPORT, DEF_BOUND, \ 0007 OPT_IMPORT_STAR, OPT_EXEC, OPT_BARE_EXEC 0008 0009 import weakref 0010 0011 __all__ = ["symtable", "SymbolTable", "newSymbolTable", "Class", 0012 "Function", "Symbol"] 0013 0014 def symtable(code, filename, compile_type): 0015 raw = _symtable.symtable(code, filename, compile_type) 0016 return newSymbolTable(raw[0], filename) 0017 0018 class SymbolTableFactory: 0019 def __init__(self): 0020 self.__memo = weakref.WeakValueDictionary() 0021 0022 def new(self, table, filename): 0023 if table.type == _symtable.TYPE_FUNCTION: 0024 return Function(table, filename) 0025 if table.type == _symtable.TYPE_CLASS: 0026 return Class(table, filename) 0027 return SymbolTable(table, filename) 0028 0029 def __call__(self, table, filename): 0030 key = table, filename 0031 obj = self.__memo.get(key, None) 0032 if obj is None: 0033 obj = self.__memo[key] = self.new(table, filename) 0034 return obj 0035 0036 newSymbolTable = SymbolTableFactory() 0037 0038 def is_free(flags): 0039 if (flags & (USE | DEF_FREE)) \ 0040 and (flags & (DEF_LOCAL | DEF_PARAM | DEF_GLOBAL)): 0041 return True 0042 if flags & DEF_FREE_CLASS: 0043 return True 0044 return False 0045 0046 class SymbolTable: 0047 def __init__(self, raw_table, filename): 0048 self._table = raw_table 0049 self._filename = filename 0050 self._symbols = {} 0051 0052 def __repr__(self): 0053 if self.__class__ == SymbolTable: 0054 kind = "" 0055 else: 0056 kind = "%s " % self.__class__.__name__ 0057 0058 if self._table.name == "global": 0059 return "<%sSymbolTable for module %s>" % (kind, self._filename) 0060 else: 0061 return "<%sSymbolTable for %s in %s>" % (kind, self._table.name, 0062 self._filename) 0063 0064 def get_type(self): 0065 if self._table.type == _symtable.TYPE_MODULE: 0066 return "module" 0067 if self._table.type == _symtable.TYPE_FUNCTION: 0068 return "function" 0069 if self._table.type == _symtable.TYPE_CLASS: 0070 return "class" 0071 assert self._table.type in (1, 2, 3), \ 0072 "unexpected type: %s" % self._table.type 0073 0074 def get_id(self): 0075 return self._table.id 0076 0077 def get_name(self): 0078 return self._table.name 0079 0080 def get_lineno(self): 0081 return self._table.lineno 0082 0083 def is_optimized(self): 0084 return bool(self._table.type == _symtable.TYPE_FUNCTION 0085 and not self._table.optimized) 0086 0087 def is_nested(self): 0088 return bool(self._table.nested) 0089 0090 def has_children(self): 0091 return bool(self._table.children) 0092 0093 def has_exec(self): 0094 """Return true if the scope uses exec""" 0095 return bool(self._table.optimized & (OPT_EXEC | OPT_BARE_EXEC)) 0096 0097 def has_import_star(self): 0098 """Return true if the scope uses import *""" 0099 return bool(self._table.optimized & OPT_IMPORT_STAR) 0100 0101 def get_identifiers(self): 0102 return self._table.symbols.keys() 0103 0104 def lookup(self, name): 0105 sym = self._symbols.get(name) 0106 if sym is None: 0107 flags = self._table.symbols[name] 0108 namespaces = self.__check_children(name) 0109 sym = self._symbols[name] = Symbol(name, flags, namespaces) 0110 return sym 0111 0112 def get_symbols(self): 0113 return [self.lookup(ident) for ident in self.get_identifiers()] 0114 0115 def __check_children(self, name): 0116 return [newSymbolTable(st, self._filename) 0117 for st in self._table.children 0118 if st.name == name] 0119 0120 def get_children(self): 0121 return [newSymbolTable(st, self._filename) 0122 for st in self._table.children] 0123 0124 class Function(SymbolTable): 0125 0126 # Default values for instance variables 0127 __params = None 0128 __locals = None 0129 __frees = None 0130 __globals = None 0131 0132 def __idents_matching(self, test_func): 0133 return tuple([ident for ident in self.get_identifiers() 0134 if test_func(self._table.symbols[ident])]) 0135 0136 def get_parameters(self): 0137 if self.__params is None: 0138 self.__params = self.__idents_matching(lambda x:x & DEF_PARAM) 0139 return self.__params 0140 0141 def get_locals(self): 0142 if self.__locals is None: 0143 self.__locals = self.__idents_matching(lambda x:x & DEF_BOUND) 0144 return self.__locals 0145 0146 def get_globals(self): 0147 if self.__globals is None: 0148 glob = DEF_GLOBAL | DEF_FREE_GLOBAL 0149 self.__globals = self.__idents_matching(lambda x:x & glob) 0150 return self.__globals 0151 0152 def get_frees(self): 0153 if self.__frees is None: 0154 self.__frees = self.__idents_matching(is_free) 0155 return self.__frees 0156 0157 class Class(SymbolTable): 0158 0159 __methods = None 0160 0161 def get_methods(self): 0162 if self.__methods is None: 0163 d = {} 0164 for st in self._table.children: 0165 d[st.name] = 1 0166 self.__methods = tuple(d) 0167 return self.__methods 0168 0169 class Symbol: 0170 def __init__(self, name, flags, namespaces=None): 0171 self.__name = name 0172 self.__flags = flags 0173 self.__namespaces = namespaces or () 0174 0175 def __repr__(self): 0176 return "<symbol '%s'>" % self.__name 0177 0178 def get_name(self): 0179 return self.__name 0180 0181 def is_referenced(self): 0182 return bool(self.__flags & _symtable.USE) 0183 0184 def is_parameter(self): 0185 return bool(self.__flags & DEF_PARAM) 0186 0187 def is_global(self): 0188 return bool((self.__flags & DEF_GLOBAL) 0189 or (self.__flags & DEF_FREE_GLOBAL)) 0190 0191 def is_vararg(self): 0192 return bool(self.__flags & DEF_STAR) 0193 0194 def is_keywordarg(self): 0195 return bool(self.__flags & DEF_DOUBLESTAR) 0196 0197 def is_local(self): 0198 return bool(self.__flags & DEF_BOUND) 0199 0200 def is_free(self): 0201 if (self.__flags & (USE | DEF_FREE)) \ 0202 and (self.__flags & (DEF_LOCAL | DEF_PARAM | DEF_GLOBAL)): 0203 return True 0204 if self.__flags & DEF_FREE_CLASS: 0205 return True 0206 return False 0207 0208 def is_imported(self): 0209 return bool(self.__flags & DEF_IMPORT) 0210 0211 def is_assigned(self): 0212 return bool(self.__flags & DEF_LOCAL) 0213 0214 def is_in_tuple(self): 0215 return bool(self.__flags & DEF_INTUPLE) 0216 0217 def is_namespace(self): 0218 """Returns true if name binding introduces new namespace. 0219 0220 If the name is used as the target of a function or class 0221 statement, this will be true. 0222 0223 Note that a single name can be bound to multiple objects. If 0224 is_namespace() is true, the name may also be bound to other 0225 objects, like an int or list, that does not introduce a new 0226 namespace. 0227 """ 0228 return bool(self.__namespaces) 0229 0230 def get_namespaces(self): 0231 """Return a list of namespaces bound to this name""" 0232 return self.__namespaces 0233 0234 def get_namespace(self): 0235 """Returns the single namespace bound to this name. 0236 0237 Raises ValueError if the name is bound to multiple namespaces. 0238 """ 0239 if len(self.__namespaces) != 1: 0240 raise ValueError, "name is bound to multiple namespaces" 0241 return self.__namespaces[0] 0242 0243 if __name__ == "__main__": 0244 import os, sys 0245 src = open(sys.argv[0]).read() 0246 mod = symtable(src, os.path.split(sys.argv[0])[1], "exec") 0247 for ident in mod.get_identifiers(): 0248 info = mod.lookup(ident) 0249 print info, info.is_local(), info.is_namespace() 0250
Generated by PyXR 0.9.4