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