home *** CD-ROM | disk | FTP | other *** search
/ PC World 2002 May / PCWorld_2002-05_cd.bin / Software / TemaCD / activepython / ActivePython-2.1.1.msi / Python21_Lib_symtable.py < prev    next >
Encoding:
Python Source  |  2001-07-26  |  7.8 KB  |  257 lines

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