ยปCore Development>Code coverage>Lib/symtable.py

Python code coverage for Lib/symtable.py

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