1
"""Interface to the compiler's internal symbol tables"""
4
from _symtable import (USE, DEF_GLOBAL, DEF_LOCAL, DEF_PARAM,
5
DEF_IMPORT, DEF_BOUND, OPT_IMPORT_STAR, OPT_EXEC, OPT_BARE_EXEC,
6
SCOPE_OFF, SCOPE_MASK, FREE, GLOBAL_IMPLICIT, GLOBAL_EXPLICIT, CELL, LOCAL)
10
__all__ = ["symtable", "SymbolTable", "Class", "Function", "Symbol"]
12
def symtable(code, filename, compile_type):
13
top = _symtable.symtable(code, filename, compile_type)
14
return _newSymbolTable(top, filename)
16
class SymbolTableFactory:
18
self.__memo = weakref.WeakValueDictionary()
20
def new(self, table, filename):
21
if table.type == _symtable.TYPE_FUNCTION:
22
return Function(table, filename)
23
if table.type == _symtable.TYPE_CLASS:
24
return Class(table, filename)
25
return SymbolTable(table, filename)
27
def __call__(self, table, filename):
29
obj = self.__memo.get(key, None)
31
obj = self.__memo[key] = self.new(table, filename)
34
_newSymbolTable = SymbolTableFactory()
37
class SymbolTable(object):
39
def __init__(self, raw_table, filename):
40
self._table = raw_table
41
self._filename = filename
45
if self.__class__ == SymbolTable:
48
kind = "%s " % self.__class__.__name__
50
if self._table.name == "global":
51
return "<{0}SymbolTable for module {1}>".format(kind, self._filename)
53
return "<{0}SymbolTable for {1} in {2}>".format(kind,
58
if self._table.type == _symtable.TYPE_MODULE:
60
if self._table.type == _symtable.TYPE_FUNCTION:
62
if self._table.type == _symtable.TYPE_CLASS:
64
assert self._table.type in (1, 2, 3), \
65
"unexpected type: {0}".format(self._table.type)
71
return self._table.name
74
return self._table.lineno
76
def is_optimized(self):
77
return bool(self._table.type == _symtable.TYPE_FUNCTION
78
and not self._table.optimized)
81
return bool(self._table.nested)
83
def has_children(self):
84
return bool(self._table.children)
87
"""Return true if the scope uses exec"""
88
return bool(self._table.optimized & (OPT_EXEC | OPT_BARE_EXEC))
90
def has_import_star(self):
91
"""Return true if the scope uses import *"""
92
return bool(self._table.optimized & OPT_IMPORT_STAR)
94
def get_identifiers(self):
95
return self._table.symbols.keys()
97
def lookup(self, name):
98
sym = self._symbols.get(name)
100
flags = self._table.symbols[name]
101
namespaces = self.__check_children(name)
102
sym = self._symbols[name] = Symbol(name, flags, namespaces)
105
def get_symbols(self):
106
return [self.lookup(ident) for ident in self.get_identifiers()]
108
def __check_children(self, name):
109
return [_newSymbolTable(st, self._filename)
110
for st in self._table.children
113
def get_children(self):
114
return [_newSymbolTable(st, self._filename)
115
for st in self._table.children]
118
class Function(SymbolTable):
120
# Default values for instance variables
126
def __idents_matching(self, test_func):
127
return tuple([ident for ident in self.get_identifiers()
128
if test_func(self._table.symbols[ident])])
130
def get_parameters(self):
131
if self.__params is None:
132
self.__params = self.__idents_matching(lambda x:x & DEF_PARAM)
135
def get_locals(self):
136
if self.__locals is None:
138
test = lambda x: ((x >> SCOPE_OFF) & SCOPE_MASK) in locs
139
self.__locals = self.__idents_matching(test)
142
def get_globals(self):
143
if self.__globals is None:
144
glob = (GLOBAL_IMPLICIT, GLOBAL_EXPLICIT)
145
test = lambda x:((x >> SCOPE_OFF) & SCOPE_MASK) in glob
146
self.__globals = self.__idents_matching(test)
147
return self.__globals
150
if self.__frees is None:
151
is_free = lambda x:((x >> SCOPE_OFF) & SCOPE_MASK) == FREE
152
self.__frees = self.__idents_matching(is_free)
156
class Class(SymbolTable):
160
def get_methods(self):
161
if self.__methods is None:
163
for st in self._table.children:
165
self.__methods = tuple(d)
166
return self.__methods
169
class Symbol(object):
171
def __init__(self, name, flags, namespaces=None):
174
self.__scope = (flags >> SCOPE_OFF) & SCOPE_MASK # like PyST_GetScope()
175
self.__namespaces = namespaces or ()
178
return "<symbol {0!r}>".format(self.__name)
183
def is_referenced(self):
184
return bool(self.__flags & _symtable.USE)
186
def is_parameter(self):
187
return bool(self.__flags & DEF_PARAM)
190
return bool(self.__scope in (GLOBAL_IMPLICIT, GLOBAL_EXPLICIT))
192
def is_declared_global(self):
193
return bool(self.__scope == GLOBAL_EXPLICIT)
196
return bool(self.__flags & DEF_BOUND)
199
return bool(self.__scope == FREE)
201
def is_imported(self):
202
return bool(self.__flags & DEF_IMPORT)
204
def is_assigned(self):
205
return bool(self.__flags & DEF_LOCAL)
207
def is_namespace(self):
208
"""Returns true if name binding introduces new namespace.
210
If the name is used as the target of a function or class
211
statement, this will be true.
213
Note that a single name can be bound to multiple objects. If
214
is_namespace() is true, the name may also be bound to other
215
objects, like an int or list, that does not introduce a new
218
return bool(self.__namespaces)
220
def get_namespaces(self):
221
"""Return a list of namespaces bound to this name"""
222
return self.__namespaces
224
def get_namespace(self):
225
"""Returns the single namespace bound to this name.
227
Raises ValueError if the name is bound to multiple namespaces.
229
if len(self.__namespaces) != 1:
230
raise ValueError, "name is bound to multiple namespaces"
231
return self.__namespaces[0]
233
if __name__ == "__main__":
235
src = open(sys.argv[0]).read()
236
mod = symtable(src, os.path.split(sys.argv[0])[1], "exec")
237
for ident in mod.get_identifiers():
238
info = mod.lookup(ident)
239
print info, info.is_local(), info.is_namespace()
1
"""Interface to the compiler's internal symbol tables"""
4
from _symtable import (USE, DEF_GLOBAL, DEF_LOCAL, DEF_PARAM,
5
DEF_IMPORT, DEF_BOUND, OPT_IMPORT_STAR, OPT_EXEC, OPT_BARE_EXEC,
6
SCOPE_OFF, SCOPE_MASK, FREE, GLOBAL_IMPLICIT, GLOBAL_EXPLICIT, CELL, LOCAL)
10
__all__ = ["symtable", "SymbolTable", "Class", "Function", "Symbol"]
12
def symtable(code, filename, compile_type):
13
top = _symtable.symtable(code, filename, compile_type)
14
return _newSymbolTable(top, filename)
16
class SymbolTableFactory:
18
self.__memo = weakref.WeakValueDictionary()
20
def new(self, table, filename):
21
if table.type == _symtable.TYPE_FUNCTION:
22
return Function(table, filename)
23
if table.type == _symtable.TYPE_CLASS:
24
return Class(table, filename)
25
return SymbolTable(table, filename)
27
def __call__(self, table, filename):
29
obj = self.__memo.get(key, None)
31
obj = self.__memo[key] = self.new(table, filename)
34
_newSymbolTable = SymbolTableFactory()
37
class SymbolTable(object):
39
def __init__(self, raw_table, filename):
40
self._table = raw_table
41
self._filename = filename
45
if self.__class__ == SymbolTable:
48
kind = "%s " % self.__class__.__name__
50
if self._table.name == "global":
51
return "<{0}SymbolTable for module {1}>".format(kind, self._filename)
53
return "<{0}SymbolTable for {1} in {2}>".format(kind,
58
if self._table.type == _symtable.TYPE_MODULE:
60
if self._table.type == _symtable.TYPE_FUNCTION:
62
if self._table.type == _symtable.TYPE_CLASS:
64
assert self._table.type in (1, 2, 3), \
65
"unexpected type: {0}".format(self._table.type)
71
return self._table.name
74
return self._table.lineno
76
def is_optimized(self):
77
return bool(self._table.type == _symtable.TYPE_FUNCTION
78
and not self._table.optimized)
81
return bool(self._table.nested)
83
def has_children(self):
84
return bool(self._table.children)
87
"""Return true if the scope uses exec"""
88
return bool(self._table.optimized & (OPT_EXEC | OPT_BARE_EXEC))
90
def has_import_star(self):
91
"""Return true if the scope uses import *"""
92
return bool(self._table.optimized & OPT_IMPORT_STAR)
94
def get_identifiers(self):
95
return self._table.symbols.keys()
97
def lookup(self, name):
98
sym = self._symbols.get(name)
100
flags = self._table.symbols[name]
101
namespaces = self.__check_children(name)
102
sym = self._symbols[name] = Symbol(name, flags, namespaces)
105
def get_symbols(self):
106
return [self.lookup(ident) for ident in self.get_identifiers()]
108
def __check_children(self, name):
109
return [_newSymbolTable(st, self._filename)
110
for st in self._table.children
113
def get_children(self):
114
return [_newSymbolTable(st, self._filename)
115
for st in self._table.children]
118
class Function(SymbolTable):
120
# Default values for instance variables
126
def __idents_matching(self, test_func):
127
return tuple([ident for ident in self.get_identifiers()
128
if test_func(self._table.symbols[ident])])
130
def get_parameters(self):
131
if self.__params is None:
132
self.__params = self.__idents_matching(lambda x:x & DEF_PARAM)
135
def get_locals(self):
136
if self.__locals is None:
138
test = lambda x: ((x >> SCOPE_OFF) & SCOPE_MASK) in locs
139
self.__locals = self.__idents_matching(test)
142
def get_globals(self):
143
if self.__globals is None:
144
glob = (GLOBAL_IMPLICIT, GLOBAL_EXPLICIT)
145
test = lambda x:((x >> SCOPE_OFF) & SCOPE_MASK) in glob
146
self.__globals = self.__idents_matching(test)
147
return self.__globals
150
if self.__frees is None:
151
is_free = lambda x:((x >> SCOPE_OFF) & SCOPE_MASK) == FREE
152
self.__frees = self.__idents_matching(is_free)
156
class Class(SymbolTable):
160
def get_methods(self):
161
if self.__methods is None:
163
for st in self._table.children:
165
self.__methods = tuple(d)
166
return self.__methods
169
class Symbol(object):
171
def __init__(self, name, flags, namespaces=None):
174
self.__scope = (flags >> SCOPE_OFF) & SCOPE_MASK # like PyST_GetScope()
175
self.__namespaces = namespaces or ()
178
return "<symbol {0!r}>".format(self.__name)
183
def is_referenced(self):
184
return bool(self.__flags & _symtable.USE)
186
def is_parameter(self):
187
return bool(self.__flags & DEF_PARAM)
190
return bool(self.__scope in (GLOBAL_IMPLICIT, GLOBAL_EXPLICIT))
192
def is_declared_global(self):
193
return bool(self.__scope == GLOBAL_EXPLICIT)
196
return bool(self.__flags & DEF_BOUND)
199
return bool(self.__scope == FREE)
201
def is_imported(self):
202
return bool(self.__flags & DEF_IMPORT)
204
def is_assigned(self):
205
return bool(self.__flags & DEF_LOCAL)
207
def is_namespace(self):
208
"""Returns true if name binding introduces new namespace.
210
If the name is used as the target of a function or class
211
statement, this will be true.
213
Note that a single name can be bound to multiple objects. If
214
is_namespace() is true, the name may also be bound to other
215
objects, like an int or list, that does not introduce a new
218
return bool(self.__namespaces)
220
def get_namespaces(self):
221
"""Return a list of namespaces bound to this name"""
222
return self.__namespaces
224
def get_namespace(self):
225
"""Returns the single namespace bound to this name.
227
Raises ValueError if the name is bound to multiple namespaces.
229
if len(self.__namespaces) != 1:
230
raise ValueError, "name is bound to multiple namespaces"
231
return self.__namespaces[0]
233
if __name__ == "__main__":
235
src = open(sys.argv[0]).read()
236
mod = symtable(src, os.path.split(sys.argv[0])[1], "exec")
237
for ident in mod.get_identifiers():
238
info = mod.lookup(ident)
239
print info, info.is_local(), info.is_namespace()