Skip to content

Commit 55e00f2

Browse files
committed
Merged revisions 65715,65724,65726,65732,65736-65739,65775 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r65715 | benjamin.peterson | 2008-08-16 16:04:16 -0500 (Sat, 16 Aug 2008) | 1 line add some documentation for symtable ........ r65724 | benjamin.peterson | 2008-08-16 17:11:33 -0500 (Sat, 16 Aug 2008) | 2 lines include filename and line number in SyntaxError ........ r65726 | georg.brandl | 2008-08-16 17:37:05 -0500 (Sat, 16 Aug 2008) | 2 lines Review symtable docs. ........ r65732 | benjamin.peterson | 2008-08-16 18:29:40 -0500 (Sat, 16 Aug 2008) | 1 line PySTEntry's constructor is static; there's no point in a fancy API name ........ r65736 | benjamin.peterson | 2008-08-16 20:09:17 -0500 (Sat, 16 Aug 2008) | 1 line expose PySTEntry.nested so the symtable module will work ........ r65737 | benjamin.peterson | 2008-08-16 20:17:15 -0500 (Sat, 16 Aug 2008) | 1 line a few improvements ........ r65738 | benjamin.peterson | 2008-08-16 20:27:30 -0500 (Sat, 16 Aug 2008) | 1 line fix compile errors ........ r65739 | benjamin.peterson | 2008-08-16 21:23:43 -0500 (Sat, 16 Aug 2008) | 1 line uhh PySTEntry->ste_unoptimized has to be exposed too ........ r65775 | benjamin.peterson | 2008-08-17 12:13:26 -0500 (Sun, 17 Aug 2008) | 5 lines get the symtable module back in working order - Fix broken functions - Add (hopefully) extensive tests - Modernize a little ........
1 parent 8ba92f6 commit 55e00f2

File tree

7 files changed

+377
-53
lines changed

7 files changed

+377
-53
lines changed

Doc/library/language.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ These modules include:
1616

1717
parser.rst
1818
ast.rst
19+
symtable.rst
1920
symbol.rst
2021
token.rst
2122
keyword.rst

Doc/library/symtable.rst

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
:mod:`symtable` --- Access to the compiler's symbol tables
2+
==========================================================
3+
4+
.. module:: symtable
5+
:synopsis: Interface to the compiler's internal symbol tables.
6+
7+
.. moduleauthor:: Jeremy Hylton <jeremy@alum.mit.edu>
8+
.. sectionauthor:: Benjamin Peterson
9+
10+
11+
Symbol tables are generated by the compiler from AST just before bytecode is
12+
generated. The symbol table is responsible for calculating the scope of every
13+
identifier in the code. :mod:`symtable` provides an interface to examine these
14+
tables.
15+
16+
17+
Generating Symbol Tables
18+
------------------------
19+
20+
.. function:: symtable(code, filename, compile_type)
21+
22+
Return the toplevel :class:`SymbolTable` for the Python source *code*.
23+
*filename* is the name of the file containing the code. *compile_type* is
24+
like the *mode* argument to :func:`compile`.
25+
26+
27+
Examining Symbol Tables
28+
-----------------------
29+
30+
.. class:: SymbolTable
31+
32+
A namespace table for a block. The constructor is not public.
33+
34+
.. method:: get_type()
35+
36+
Return the type of the symbol table. Possible values are ``'class'``,
37+
``'module'``, and ``'function'``.
38+
39+
.. method:: get_id()
40+
41+
Return the table's identifier.
42+
43+
.. method:: get_name()
44+
45+
Return the table's name. This is the name of the class if the table is
46+
for a class, the name of the function if the table is for a function, or
47+
``'top'`` if the table is global (:meth:`get_type` returns ``'module'``).
48+
49+
.. method:: get_lineno()
50+
51+
Return the number of the first line in the block this table represents.
52+
53+
.. method:: is_optimized()
54+
55+
Return ``True`` if the locals in this table can be optimized.
56+
57+
.. method:: is_nested()
58+
59+
Return ``True`` if the block is a nested class or function.
60+
61+
.. method:: has_children()
62+
63+
Return ``True`` if the block has nested namespaces within it. These can
64+
be obtained with :meth:`get_children`.
65+
66+
.. method:: has_exec()
67+
68+
Return ``True`` if the block uses ``exec``.
69+
70+
.. method:: has_import_start()
71+
72+
Return ``True`` if the block uses a starred from-import.
73+
74+
.. method:: get_identifiers()
75+
76+
Return a list of names of symbols in this table.
77+
78+
.. method:: lookup(name)
79+
80+
Lookup *name* in the table and return a :class:`Symbol` instance.
81+
82+
.. method:: get_symbols()
83+
84+
Return a list of :class:`Symbol` instances for names in the table.
85+
86+
.. method:: get_children()
87+
88+
Return a list of the nested symbol tables.
89+
90+
91+
.. class:: Function
92+
93+
A namespace for a function or method. This class inherits
94+
:class:`SymbolTable`.
95+
96+
.. method:: get_parameters()
97+
98+
Return a tuple containing names of parameters to this function.
99+
100+
.. method:: get_locals()
101+
102+
Return a tuple containing names of locals in this function.
103+
104+
.. method:: get_globals()
105+
106+
Return a tuple containing names of globals in this function.
107+
108+
.. method:: get_frees()
109+
110+
Return a tuple containing names of free variables in this function.
111+
112+
113+
.. class:: Class
114+
115+
A namespace of a class. This class inherits :class:`SymbolTable`.
116+
117+
.. method:: get_methods()
118+
119+
Return a tuple containing the names of methods declared in the class.
120+
121+
122+
.. class:: Symbol
123+
124+
An entry in a :class:`SymbolTable` corresponding to an identifier in the
125+
source. The constructor is not public.
126+
127+
.. method:: get_name()
128+
129+
Return the symbol's name.
130+
131+
.. method:: is_referenced()
132+
133+
Return ``True`` if the symbol is used in its block.
134+
135+
.. method:: is_imported()
136+
137+
Return ``True`` if the symbol is created from an import statement.
138+
139+
.. method:: is_parameter()
140+
141+
Return ``True`` if the symbol is a parameter.
142+
143+
.. method:: is_global()
144+
145+
Return ``True`` if the symbol is global.
146+
147+
.. method:: is_vararg()
148+
149+
Return ``True`` if the symbol is a star arg (receives varargs).
150+
151+
.. method:: is_kewordarg()
152+
153+
Return ``True`` if the symbol is a two-star arg (receives keyword
154+
arguments).
155+
156+
.. method:: is_local()
157+
158+
Return ``True`` if the symbol is local to its block.
159+
160+
.. method:: is_free()
161+
162+
Return ``True`` if the symbol is referenced in its block, but not assigned
163+
to.
164+
165+
.. method:: is_assigned()
166+
167+
Return ``True`` if the symbol is assigned to in its block.
168+
169+
.. method:: is_namespace()
170+
171+
Return ``True`` if name binding introduces new namespace.
172+
173+
If the name is used as the target of a function or class statement, this
174+
will be true.
175+
176+
Note that a single name can be bound to multiple objects. If the result
177+
is ``True``, the name may also be bound to other objects, like an int or
178+
list, that does not introduce a new namespace.
179+
180+
.. method:: get_namespaces()
181+
182+
Return a list of namespaces bound to this name.
183+
184+
.. method:: get_namespace()
185+
186+
Return the namespace bound to this name. If more than one namespace is
187+
bound, a :exc:`ValueError` is raised.

Include/symtable.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ typedef struct _symtable_entry {
3636
PyObject *ste_children; /* list of child blocks */
3737
_Py_block_ty ste_type; /* module, class, or function */
3838
int ste_unoptimized; /* false if namespace is optimized */
39-
unsigned ste_nested : 1; /* true if block is nested */
39+
int ste_nested; /* true if block is nested */
4040
unsigned ste_free : 1; /* true if block has free variables */
4141
unsigned ste_child_free : 1; /* true if a child block has free vars,
4242
including free refs to globals */

Lib/symtable.py

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
"""Interface to the compiler's internal symbol tables"""
22

33
import _symtable
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
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, SCOPE_OFF, SCOPE_MASK, FREE,
8+
GLOBAL_IMPLICIT, GLOBAL_EXPLICIT)
89

910
import weakref
1011

@@ -38,15 +39,9 @@ def __call__(self, table, filename):
3839

3940
newSymbolTable = SymbolTableFactory()
4041

41-
def is_free(flags):
42-
if (flags & (USE | DEF_FREE)) \
43-
and (flags & (DEF_LOCAL | DEF_PARAM | DEF_GLOBAL)):
44-
return True
45-
if flags & DEF_FREE_CLASS:
46-
return True
47-
return False
4842

49-
class SymbolTable:
43+
class SymbolTable(object):
44+
5045
def __init__(self, raw_table, filename):
5146
self._table = raw_table
5247
self._filename = filename
@@ -59,10 +54,11 @@ def __repr__(self):
5954
kind = "%s " % self.__class__.__name__
6055

6156
if self._table.name == "global":
62-
return "<%sSymbolTable for module %s>" % (kind, self._filename)
57+
return "<{0}SymbolTable for module {1}>".format(kind, self._filename)
6358
else:
64-
return "<%sSymbolTable for %s in %s>" % (kind, self._table.name,
65-
self._filename)
59+
return "<{0}SymbolTable for {1} in {2}>".format(kind,
60+
self._table.name,
61+
self._filename)
6662

6763
def get_type(self):
6864
if self._table.type == _symtable.TYPE_MODULE:
@@ -72,7 +68,7 @@ def get_type(self):
7268
if self._table.type == _symtable.TYPE_CLASS:
7369
return "class"
7470
assert self._table.type in (1, 2, 3), \
75-
"unexpected type: %s" % self._table.type
71+
"unexpected type: {0}".format(self._table.type)
7672

7773
def get_id(self):
7874
return self._table.id
@@ -124,6 +120,7 @@ def get_children(self):
124120
return [newSymbolTable(st, self._filename)
125121
for st in self._table.children]
126122

123+
127124
class Function(SymbolTable):
128125

129126
# Default values for instance variables
@@ -148,15 +145,18 @@ def get_locals(self):
148145

149146
def get_globals(self):
150147
if self.__globals is None:
151-
glob = DEF_GLOBAL | DEF_FREE_GLOBAL
152-
self.__globals = self.__idents_matching(lambda x:x & glob)
148+
glob = (GLOBAL_IMPLICIT, GLOBAL_EXPLICIT)
149+
test = lambda x:((x >> SCOPE_OFF) & SCOPE_MASK) in glob
150+
self.__globals = self.__idents_matching(test)
153151
return self.__globals
154152

155153
def get_frees(self):
156154
if self.__frees is None:
155+
is_free = lambda x:((x >> SCOPE_OFF) & SCOPE_MASK) == FREE
157156
self.__frees = self.__idents_matching(is_free)
158157
return self.__frees
159158

159+
160160
class Class(SymbolTable):
161161

162162
__methods = None
@@ -169,14 +169,17 @@ def get_methods(self):
169169
self.__methods = tuple(d)
170170
return self.__methods
171171

172-
class Symbol:
172+
173+
class Symbol(object):
174+
173175
def __init__(self, name, flags, namespaces=None):
174176
self.__name = name
175177
self.__flags = flags
178+
self.__scope = (flags >> SCOPE_OFF) & SCOPE_MASK # like PyST_GetScope()
176179
self.__namespaces = namespaces or ()
177180

178181
def __repr__(self):
179-
return "<symbol '%s'>" % self.__name
182+
return "<symbol {0!r}>".format(self.__name)
180183

181184
def get_name(self):
182185
return self.__name
@@ -188,8 +191,7 @@ def is_parameter(self):
188191
return bool(self.__flags & DEF_PARAM)
189192

190193
def is_global(self):
191-
return bool((self.__flags & DEF_GLOBAL)
192-
or (self.__flags & DEF_FREE_GLOBAL))
194+
return bool(self.__scope in (GLOBAL_IMPLICIT, GLOBAL_EXPLICIT))
193195

194196
def is_vararg(self):
195197
return bool(self.__flags & DEF_STAR)
@@ -201,12 +203,7 @@ def is_local(self):
201203
return bool(self.__flags & DEF_BOUND)
202204

203205
def is_free(self):
204-
if (self.__flags & (USE | DEF_FREE)) \
205-
and (self.__flags & (DEF_LOCAL | DEF_PARAM | DEF_GLOBAL)):
206-
return True
207-
if self.__flags & DEF_FREE_CLASS:
208-
return True
209-
return False
206+
return bool(self.__scope == FREE)
210207

211208
def is_imported(self):
212209
return bool(self.__flags & DEF_IMPORT)

0 commit comments

Comments
 (0)