10a8c90248264a8b26970b4473770bcc3df8515fJosh Gao"""Interface to the compiler's internal symbol tables""" 20a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 30a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport _symtable 40a8c90248264a8b26970b4473770bcc3df8515fJosh Gaofrom _symtable import (USE, DEF_GLOBAL, DEF_LOCAL, DEF_PARAM, 50a8c90248264a8b26970b4473770bcc3df8515fJosh Gao DEF_IMPORT, DEF_BOUND, OPT_IMPORT_STAR, OPT_EXEC, OPT_BARE_EXEC, 60a8c90248264a8b26970b4473770bcc3df8515fJosh Gao SCOPE_OFF, SCOPE_MASK, FREE, GLOBAL_IMPLICIT, GLOBAL_EXPLICIT, CELL, LOCAL) 70a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 80a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport weakref 90a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 100a8c90248264a8b26970b4473770bcc3df8515fJosh Gao__all__ = ["symtable", "SymbolTable", "Class", "Function", "Symbol"] 110a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 120a8c90248264a8b26970b4473770bcc3df8515fJosh Gaodef symtable(code, filename, compile_type): 130a8c90248264a8b26970b4473770bcc3df8515fJosh Gao raw = _symtable.symtable(code, filename, compile_type) 140a8c90248264a8b26970b4473770bcc3df8515fJosh Gao for top in raw.itervalues(): 150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if top.name == 'top': 160a8c90248264a8b26970b4473770bcc3df8515fJosh Gao break 170a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return _newSymbolTable(top, filename) 180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 190a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass SymbolTableFactory: 200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def __init__(self): 210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.__memo = weakref.WeakValueDictionary() 220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def new(self, table, filename): 240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if table.type == _symtable.TYPE_FUNCTION: 250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return Function(table, filename) 260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if table.type == _symtable.TYPE_CLASS: 270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return Class(table, filename) 280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return SymbolTable(table, filename) 290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def __call__(self, table, filename): 310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao key = table, filename 320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao obj = self.__memo.get(key, None) 330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if obj is None: 340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao obj = self.__memo[key] = self.new(table, filename) 350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return obj 360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao_newSymbolTable = SymbolTableFactory() 380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 400a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass SymbolTable(object): 410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def __init__(self, raw_table, filename): 430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self._table = raw_table 440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self._filename = filename 450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self._symbols = {} 460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 470a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def __repr__(self): 480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if self.__class__ == SymbolTable: 490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao kind = "" 500a8c90248264a8b26970b4473770bcc3df8515fJosh Gao else: 510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao kind = "%s " % self.__class__.__name__ 520a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if self._table.name == "global": 540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return "<{0}SymbolTable for module {1}>".format(kind, self._filename) 550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao else: 560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return "<{0}SymbolTable for {1} in {2}>".format(kind, 570a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self._table.name, 580a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self._filename) 590a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 600a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def get_type(self): 610a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if self._table.type == _symtable.TYPE_MODULE: 620a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return "module" 630a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if self._table.type == _symtable.TYPE_FUNCTION: 640a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return "function" 650a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if self._table.type == _symtable.TYPE_CLASS: 660a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return "class" 670a8c90248264a8b26970b4473770bcc3df8515fJosh Gao assert self._table.type in (1, 2, 3), \ 680a8c90248264a8b26970b4473770bcc3df8515fJosh Gao "unexpected type: {0}".format(self._table.type) 690a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 700a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def get_id(self): 710a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return self._table.id 720a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 730a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def get_name(self): 740a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return self._table.name 750a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 760a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def get_lineno(self): 770a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return self._table.lineno 780a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 790a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def is_optimized(self): 800a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return bool(self._table.type == _symtable.TYPE_FUNCTION 810a8c90248264a8b26970b4473770bcc3df8515fJosh Gao and not self._table.optimized) 820a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 830a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def is_nested(self): 840a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return bool(self._table.nested) 850a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 860a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def has_children(self): 870a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return bool(self._table.children) 880a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 890a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def has_exec(self): 900a8c90248264a8b26970b4473770bcc3df8515fJosh Gao """Return true if the scope uses exec""" 910a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return bool(self._table.optimized & (OPT_EXEC | OPT_BARE_EXEC)) 920a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 930a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def has_import_star(self): 940a8c90248264a8b26970b4473770bcc3df8515fJosh Gao """Return true if the scope uses import *""" 950a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return bool(self._table.optimized & OPT_IMPORT_STAR) 960a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 970a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def get_identifiers(self): 980a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return self._table.symbols.keys() 990a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1000a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def lookup(self, name): 1010a8c90248264a8b26970b4473770bcc3df8515fJosh Gao sym = self._symbols.get(name) 1020a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if sym is None: 1030a8c90248264a8b26970b4473770bcc3df8515fJosh Gao flags = self._table.symbols[name] 1040a8c90248264a8b26970b4473770bcc3df8515fJosh Gao namespaces = self.__check_children(name) 1050a8c90248264a8b26970b4473770bcc3df8515fJosh Gao sym = self._symbols[name] = Symbol(name, flags, namespaces) 1060a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return sym 1070a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1080a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def get_symbols(self): 1090a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return [self.lookup(ident) for ident in self.get_identifiers()] 1100a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1110a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def __check_children(self, name): 1120a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return [_newSymbolTable(st, self._filename) 1130a8c90248264a8b26970b4473770bcc3df8515fJosh Gao for st in self._table.children 1140a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if st.name == name] 1150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1160a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def get_children(self): 1170a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return [_newSymbolTable(st, self._filename) 1180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao for st in self._table.children] 1190a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1210a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass Function(SymbolTable): 1220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Default values for instance variables 1240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao __params = None 1250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao __locals = None 1260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao __frees = None 1270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao __globals = None 1280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def __idents_matching(self, test_func): 1300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return tuple([ident for ident in self.get_identifiers() 1310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if test_func(self._table.symbols[ident])]) 1320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def get_parameters(self): 1340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if self.__params is None: 1350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.__params = self.__idents_matching(lambda x:x & DEF_PARAM) 1360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return self.__params 1370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def get_locals(self): 1390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if self.__locals is None: 1400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao locs = (LOCAL, CELL) 1410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao test = lambda x: ((x >> SCOPE_OFF) & SCOPE_MASK) in locs 1420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.__locals = self.__idents_matching(test) 1430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return self.__locals 1440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def get_globals(self): 1460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if self.__globals is None: 1470a8c90248264a8b26970b4473770bcc3df8515fJosh Gao glob = (GLOBAL_IMPLICIT, GLOBAL_EXPLICIT) 1480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao test = lambda x:((x >> SCOPE_OFF) & SCOPE_MASK) in glob 1490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.__globals = self.__idents_matching(test) 1500a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return self.__globals 1510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1520a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def get_frees(self): 1530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if self.__frees is None: 1540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao is_free = lambda x:((x >> SCOPE_OFF) & SCOPE_MASK) == FREE 1550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.__frees = self.__idents_matching(is_free) 1560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return self.__frees 1570a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1580a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1590a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass Class(SymbolTable): 1600a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1610a8c90248264a8b26970b4473770bcc3df8515fJosh Gao __methods = None 1620a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1630a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def get_methods(self): 1640a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if self.__methods is None: 1650a8c90248264a8b26970b4473770bcc3df8515fJosh Gao d = {} 1660a8c90248264a8b26970b4473770bcc3df8515fJosh Gao for st in self._table.children: 1670a8c90248264a8b26970b4473770bcc3df8515fJosh Gao d[st.name] = 1 1680a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.__methods = tuple(d) 1690a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return self.__methods 1700a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1710a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1720a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass Symbol(object): 1730a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1740a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def __init__(self, name, flags, namespaces=None): 1750a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.__name = name 1760a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.__flags = flags 1770a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.__scope = (flags >> SCOPE_OFF) & SCOPE_MASK # like PyST_GetScope() 1780a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.__namespaces = namespaces or () 1790a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1800a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def __repr__(self): 1810a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return "<symbol {0!r}>".format(self.__name) 1820a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1830a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def get_name(self): 1840a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return self.__name 1850a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1860a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def is_referenced(self): 1870a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return bool(self.__flags & _symtable.USE) 1880a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1890a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def is_parameter(self): 1900a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return bool(self.__flags & DEF_PARAM) 1910a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1920a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def is_global(self): 1930a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return bool(self.__scope in (GLOBAL_IMPLICIT, GLOBAL_EXPLICIT)) 1940a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1950a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def is_declared_global(self): 1960a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return bool(self.__scope == GLOBAL_EXPLICIT) 1970a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1980a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def is_local(self): 1990a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return bool(self.__flags & DEF_BOUND) 2000a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 2010a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def is_free(self): 2020a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return bool(self.__scope == FREE) 2030a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 2040a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def is_imported(self): 2050a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return bool(self.__flags & DEF_IMPORT) 2060a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 2070a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def is_assigned(self): 2080a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return bool(self.__flags & DEF_LOCAL) 2090a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 2100a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def is_namespace(self): 2110a8c90248264a8b26970b4473770bcc3df8515fJosh Gao """Returns true if name binding introduces new namespace. 2120a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 2130a8c90248264a8b26970b4473770bcc3df8515fJosh Gao If the name is used as the target of a function or class 2140a8c90248264a8b26970b4473770bcc3df8515fJosh Gao statement, this will be true. 2150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 2160a8c90248264a8b26970b4473770bcc3df8515fJosh Gao Note that a single name can be bound to multiple objects. If 2170a8c90248264a8b26970b4473770bcc3df8515fJosh Gao is_namespace() is true, the name may also be bound to other 2180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao objects, like an int or list, that does not introduce a new 2190a8c90248264a8b26970b4473770bcc3df8515fJosh Gao namespace. 2200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao """ 2210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return bool(self.__namespaces) 2220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 2230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def get_namespaces(self): 2240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao """Return a list of namespaces bound to this name""" 2250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return self.__namespaces 2260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 2270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def get_namespace(self): 2280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao """Returns the single namespace bound to this name. 2290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 2300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao Raises ValueError if the name is bound to multiple namespaces. 2310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao """ 2320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if len(self.__namespaces) != 1: 2330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao raise ValueError, "name is bound to multiple namespaces" 2340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return self.__namespaces[0] 2350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 2360a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoif __name__ == "__main__": 2370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao import os, sys 2380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao src = open(sys.argv[0]).read() 2390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao mod = symtable(src, os.path.split(sys.argv[0])[1], "exec") 2400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao for ident in mod.get_identifiers(): 2410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao info = mod.lookup(ident) 2420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print info, info.is_local(), info.is_namespace() 243