1 """Interface to the compiler's internal symbol tables"""
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
11 __all__
= ["symtable", "SymbolTable", "newSymbolTable", "Class",
14 def symtable(code
, filename
, compile_type
):
15 raw
= _symtable
.symtable(code
, filename
, compile_type
)
16 return newSymbolTable(raw
[0], filename
)
18 class SymbolTableFactory
:
20 self
.__memo
= weakref
.WeakValueDictionary()
22 def new(self
, table
, filename
):
23 if table
.type == _symtable
.TYPE_FUNCTION
:
24 return Function(table
, filename
)
25 if table
.type == _symtable
.TYPE_CLASS
:
26 return Class(table
, filename
)
27 return SymbolTable(table
, filename
)
29 def __call__(self
, table
, filename
):
31 obj
= self
.__memo
.get(key
, None)
33 obj
= self
.__memo
[key
] = self
.new(table
, filename
)
36 newSymbolTable
= SymbolTableFactory()
39 """Helper to force boolean result to 1 or 0"""
45 if (flags
& (USE | DEF_FREE
)) \
46 and (flags
& (DEF_LOCAL | DEF_PARAM | DEF_GLOBAL
)):
48 if flags
& DEF_FREE_CLASS
:
53 def __init__(self
, raw_table
, filename
):
54 self
._table
= raw_table
55 self
._filename
= filename
59 if self
.__class
__ == SymbolTable
:
62 kind
= "%s " % self
.__class
__.__name
__
64 if self
._table
.name
== "global":
65 return "<%sSymbolTable for module %s>" % (kind
, self
._filename
)
67 return "<%sSymbolTable for %s in %s>" % (kind
, self
._table
.name
,
71 if self
._table
.type == _symtable
.TYPE_MODULE
:
73 if self
._table
.type == _symtable
.TYPE_FUNCTION
:
75 if self
._table
.type == _symtable
.TYPE_CLASS
:
77 assert self
._table
.type in (1, 2, 3), \
78 "unexpected type: %s" % self
._table
.type
84 return self
._table
.name
87 return self
._table
.lineno
89 def is_optimized(self
):
90 return bool(self
._table
.type == _symtable
.TYPE_FUNCTION
91 and not self
._table
.optimized
)
94 return bool(self
._table
.nested
)
96 def has_children(self
):
97 return bool(self
._table
.children
)
100 """Return true if the scope uses exec"""
101 return bool(self
._table
.optimized
& (OPT_EXEC | OPT_BARE_EXEC
))
103 def has_import_star(self
):
104 """Return true if the scope uses import *"""
105 return bool(self
._table
.optimized
& OPT_IMPORT_STAR
)
107 def get_identifiers(self
):
108 return self
._table
.symbols
.keys()
110 def lookup(self
, name
):
111 sym
= self
._symbols
.get(name
)
113 flags
= self
._table
.symbols
[name
]
114 namespaces
= self
.__check
_children
(name
)
115 sym
= self
._symbols
[name
] = Symbol(name
, flags
, namespaces
)
118 def get_symbols(self
):
119 return [self
.lookup(ident
) for ident
in self
.get_identifiers()]
121 def __check_children(self
, name
):
122 return [newSymbolTable(st
, self
._filename
)
123 for st
in self
._table
.children
126 def get_children(self
):
127 return [newSymbolTable(st
, self
._filename
)
128 for st
in self
._table
.children
]
130 class Function(SymbolTable
):
132 # Default values for instance variables
138 def __idents_matching(self
, test_func
):
139 return tuple([ident
for ident
in self
.get_identifiers()
140 if test_func(self
._table
.symbols
[ident
])])
142 def get_parameters(self
):
143 if self
.__params
is None:
144 self
.__params
= self
.__idents
_matching
(lambda x
:x
& DEF_PARAM
)
147 def get_locals(self
):
148 if self
.__locals
is None:
149 self
.__locals
= self
.__idents
_matching
(lambda x
:x
& DEF_BOUND
)
152 def get_globals(self
):
153 if self
.__globals
is None:
154 glob
= DEF_GLOBAL | DEF_FREE_GLOBAL
155 self
.__globals
= self
.__idents
_matching
(lambda x
:x
& glob
)
156 return self
.__globals
159 if self
.__frees
is None:
160 self
.__frees
= self
.__idents
_matching
(is_free
)
163 class Class(SymbolTable
):
167 def get_methods(self
):
168 if self
.__methods
is None:
170 for st
in self
._table
.children
:
172 self
.__methods
= tuple(d
.keys())
173 return self
.__methods
176 def __init__(self
, name
, flags
, namespaces
=None):
179 self
.__namespaces
= namespaces
or ()
182 return "<symbol '%s'>" % self
.__name
187 def is_referenced(self
):
188 return bool(self
.__flags
& _symtable
.USE
)
190 def is_parameter(self
):
191 return bool(self
.__flags
& DEF_PARAM
)
194 return bool((self
.__flags
& DEF_GLOBAL
)
195 or (self
.__flags
& DEF_FREE_GLOBAL
))
198 return bool(self
.__flags
& DEF_STAR
)
200 def is_keywordarg(self
):
201 return bool(self
.__flags
& DEF_DOUBLESTAR
)
204 return bool(self
.__flags
& DEF_BOUND
)
207 if (self
.__flags
& (USE | DEF_FREE
)) \
208 and (self
.__flags
& (DEF_LOCAL | DEF_PARAM | DEF_GLOBAL
)):
210 if self
.__flags
& DEF_FREE_CLASS
:
214 def is_imported(self
):
215 return bool(self
.__flags
& DEF_IMPORT
)
217 def is_assigned(self
):
218 return bool(self
.__flags
& DEF_LOCAL
)
220 def is_in_tuple(self
):
221 return bool(self
.__flags
& DEF_INTUPLE
)
223 def is_namespace(self
):
224 """Returns true if name binding introduces new namespace.
226 If the name is used as the target of a function or class
227 statement, this will be true.
229 Note that a single name can be bound to multiple objects. If
230 is_namespace() is true, the name may also be bound to other
231 objects, like an int or list, that does not introduce a new
234 return bool(self
.__namespaces
)
236 def get_namespaces(self
):
237 """Return a list of namespaces bound to this name"""
238 return self
.__namespaces
240 def get_namespace(self
):
241 """Returns the single namespace bound to this name.
243 Raises ValueError if the name is bound to multiple namespaces.
245 if len(self
.__namespaces
) != 1:
246 raise ValueError, "name is bound to multiple namespaces"
247 return self
.__namespaces
[0]
249 if __name__
== "__main__":
251 src
= open(sys
.argv
[0]).read()
252 mod
= symtable(src
, os
.path
.split(sys
.argv
[0])[1], "exec")
253 for ident
in mod
.get_identifiers():
254 info
= mod
.lookup(ident
)
255 print info
, info
.is_local(), info
.is_namespace()