python-2.5.2/win32/Lib/symtable.py
changeset 0 ae805ac0140d
equal deleted inserted replaced
-1:000000000000 0:ae805ac0140d
       
     1 """Interface to the compiler's internal symbol tables"""
       
     2 
       
     3 import _symtable
       
     4 from _symtable import USE, DEF_GLOBAL, DEF_LOCAL, DEF_PARAM, \
       
     5      DEF_STAR, DEF_DOUBLESTAR, DEF_INTUPLE, DEF_FREE, \
       
     6      DEF_FREE_GLOBAL, DEF_FREE_CLASS, DEF_IMPORT, DEF_BOUND, \
       
     7      OPT_IMPORT_STAR, OPT_EXEC, OPT_BARE_EXEC
       
     8 
       
     9 import weakref
       
    10 
       
    11 __all__ = ["symtable", "SymbolTable", "newSymbolTable", "Class",
       
    12            "Function", "Symbol"]
       
    13 
       
    14 def symtable(code, filename, compile_type):
       
    15     raw = _symtable.symtable(code, filename, compile_type)
       
    16     for top in raw.itervalues():
       
    17         if top.name == 'top':
       
    18             break
       
    19     return newSymbolTable(top, filename)
       
    20 
       
    21 class SymbolTableFactory:
       
    22     def __init__(self):
       
    23         self.__memo = weakref.WeakValueDictionary()
       
    24 
       
    25     def new(self, table, filename):
       
    26         if table.type == _symtable.TYPE_FUNCTION:
       
    27             return Function(table, filename)
       
    28         if table.type == _symtable.TYPE_CLASS:
       
    29             return Class(table, filename)
       
    30         return SymbolTable(table, filename)
       
    31 
       
    32     def __call__(self, table, filename):
       
    33         key = table, filename
       
    34         obj = self.__memo.get(key, None)
       
    35         if obj is None:
       
    36             obj = self.__memo[key] = self.new(table, filename)
       
    37         return obj
       
    38 
       
    39 newSymbolTable = SymbolTableFactory()
       
    40 
       
    41 def is_free(flags):
       
    42     if (flags & (USE | DEF_FREE)) \
       
    43        and (flags & (DEF_LOCAL | DEF_PARAM | DEF_GLOBAL)):
       
    44         return True
       
    45     if flags & DEF_FREE_CLASS:
       
    46         return True
       
    47     return False
       
    48 
       
    49 class SymbolTable:
       
    50     def __init__(self, raw_table, filename):
       
    51         self._table = raw_table
       
    52         self._filename = filename
       
    53         self._symbols = {}
       
    54 
       
    55     def __repr__(self):
       
    56         if self.__class__ == SymbolTable:
       
    57             kind = ""
       
    58         else:
       
    59             kind = "%s " % self.__class__.__name__
       
    60 
       
    61         if self._table.name == "global":
       
    62             return "<%sSymbolTable for module %s>" % (kind, self._filename)
       
    63         else:
       
    64             return "<%sSymbolTable for %s in %s>" % (kind, self._table.name,
       
    65                                                      self._filename)
       
    66 
       
    67     def get_type(self):
       
    68         if self._table.type == _symtable.TYPE_MODULE:
       
    69             return "module"
       
    70         if self._table.type == _symtable.TYPE_FUNCTION:
       
    71             return "function"
       
    72         if self._table.type == _symtable.TYPE_CLASS:
       
    73             return "class"
       
    74         assert self._table.type in (1, 2, 3), \
       
    75                "unexpected type: %s" % self._table.type
       
    76 
       
    77     def get_id(self):
       
    78         return self._table.id
       
    79 
       
    80     def get_name(self):
       
    81         return self._table.name
       
    82 
       
    83     def get_lineno(self):
       
    84         return self._table.lineno
       
    85 
       
    86     def is_optimized(self):
       
    87         return bool(self._table.type == _symtable.TYPE_FUNCTION
       
    88                     and not self._table.optimized)
       
    89 
       
    90     def is_nested(self):
       
    91         return bool(self._table.nested)
       
    92 
       
    93     def has_children(self):
       
    94         return bool(self._table.children)
       
    95 
       
    96     def has_exec(self):
       
    97         """Return true if the scope uses exec"""
       
    98         return bool(self._table.optimized & (OPT_EXEC | OPT_BARE_EXEC))
       
    99 
       
   100     def has_import_star(self):
       
   101         """Return true if the scope uses import *"""
       
   102         return bool(self._table.optimized & OPT_IMPORT_STAR)
       
   103 
       
   104     def get_identifiers(self):
       
   105         return self._table.symbols.keys()
       
   106 
       
   107     def lookup(self, name):
       
   108         sym = self._symbols.get(name)
       
   109         if sym is None:
       
   110             flags = self._table.symbols[name]
       
   111             namespaces = self.__check_children(name)
       
   112             sym = self._symbols[name] = Symbol(name, flags, namespaces)
       
   113         return sym
       
   114 
       
   115     def get_symbols(self):
       
   116         return [self.lookup(ident) for ident in self.get_identifiers()]
       
   117 
       
   118     def __check_children(self, name):
       
   119         return [newSymbolTable(st, self._filename)
       
   120                 for st in self._table.children
       
   121                 if st.name == name]
       
   122 
       
   123     def get_children(self):
       
   124         return [newSymbolTable(st, self._filename)
       
   125                 for st in self._table.children]
       
   126 
       
   127 class Function(SymbolTable):
       
   128 
       
   129     # Default values for instance variables
       
   130     __params = None
       
   131     __locals = None
       
   132     __frees = None
       
   133     __globals = None
       
   134 
       
   135     def __idents_matching(self, test_func):
       
   136         return tuple([ident for ident in self.get_identifiers()
       
   137                       if test_func(self._table.symbols[ident])])
       
   138 
       
   139     def get_parameters(self):
       
   140         if self.__params is None:
       
   141             self.__params = self.__idents_matching(lambda x:x & DEF_PARAM)
       
   142         return self.__params
       
   143 
       
   144     def get_locals(self):
       
   145         if self.__locals is None:
       
   146             self.__locals = self.__idents_matching(lambda x:x & DEF_BOUND)
       
   147         return self.__locals
       
   148 
       
   149     def get_globals(self):
       
   150         if self.__globals is None:
       
   151             glob = DEF_GLOBAL | DEF_FREE_GLOBAL
       
   152             self.__globals = self.__idents_matching(lambda x:x & glob)
       
   153         return self.__globals
       
   154 
       
   155     def get_frees(self):
       
   156         if self.__frees is None:
       
   157             self.__frees = self.__idents_matching(is_free)
       
   158         return self.__frees
       
   159 
       
   160 class Class(SymbolTable):
       
   161 
       
   162     __methods = None
       
   163 
       
   164     def get_methods(self):
       
   165         if self.__methods is None:
       
   166             d = {}
       
   167             for st in self._table.children:
       
   168                 d[st.name] = 1
       
   169             self.__methods = tuple(d)
       
   170         return self.__methods
       
   171 
       
   172 class Symbol:
       
   173     def __init__(self, name, flags, namespaces=None):
       
   174         self.__name = name
       
   175         self.__flags = flags
       
   176         self.__namespaces = namespaces or ()
       
   177 
       
   178     def __repr__(self):
       
   179         return "<symbol '%s'>" % self.__name
       
   180 
       
   181     def get_name(self):
       
   182         return self.__name
       
   183 
       
   184     def is_referenced(self):
       
   185         return bool(self.__flags & _symtable.USE)
       
   186 
       
   187     def is_parameter(self):
       
   188         return bool(self.__flags & DEF_PARAM)
       
   189 
       
   190     def is_global(self):
       
   191         return bool((self.__flags & DEF_GLOBAL)
       
   192                     or (self.__flags & DEF_FREE_GLOBAL))
       
   193 
       
   194     def is_vararg(self):
       
   195         return bool(self.__flags & DEF_STAR)
       
   196 
       
   197     def is_keywordarg(self):
       
   198         return bool(self.__flags & DEF_DOUBLESTAR)
       
   199 
       
   200     def is_local(self):
       
   201         return bool(self.__flags & DEF_BOUND)
       
   202 
       
   203     def is_free(self):
       
   204         if (self.__flags & (USE | DEF_FREE)) \
       
   205             and (self.__flags & (DEF_LOCAL | DEF_PARAM | DEF_GLOBAL)):
       
   206             return True
       
   207         if self.__flags & DEF_FREE_CLASS:
       
   208             return True
       
   209         return False
       
   210 
       
   211     def is_imported(self):
       
   212         return bool(self.__flags & DEF_IMPORT)
       
   213 
       
   214     def is_assigned(self):
       
   215         return bool(self.__flags & DEF_LOCAL)
       
   216 
       
   217     def is_in_tuple(self):
       
   218         return bool(self.__flags & DEF_INTUPLE)
       
   219 
       
   220     def is_namespace(self):
       
   221         """Returns true if name binding introduces new namespace.
       
   222 
       
   223         If the name is used as the target of a function or class
       
   224         statement, this will be true.
       
   225 
       
   226         Note that a single name can be bound to multiple objects.  If
       
   227         is_namespace() is true, the name may also be bound to other
       
   228         objects, like an int or list, that does not introduce a new
       
   229         namespace.
       
   230         """
       
   231         return bool(self.__namespaces)
       
   232 
       
   233     def get_namespaces(self):
       
   234         """Return a list of namespaces bound to this name"""
       
   235         return self.__namespaces
       
   236 
       
   237     def get_namespace(self):
       
   238         """Returns the single namespace bound to this name.
       
   239 
       
   240         Raises ValueError if the name is bound to multiple namespaces.
       
   241         """
       
   242         if len(self.__namespaces) != 1:
       
   243             raise ValueError, "name is bound to multiple namespaces"
       
   244         return self.__namespaces[0]
       
   245 
       
   246 if __name__ == "__main__":
       
   247     import os, sys
       
   248     src = open(sys.argv[0]).read()
       
   249     mod = symtable(src, os.path.split(sys.argv[0])[1], "exec")
       
   250     for ident in mod.get_identifiers():
       
   251         info = mod.lookup(ident)
       
   252         print info, info.is_local(), info.is_namespace()