Add generator detection to symbol table.

Fix bug in handling of statements like "l[x:y] = 2".  The visitor was
treating this as assignments to l, x, and y!
This commit is contained in:
Jeremy Hylton 2001-08-29 18:10:51 +00:00
parent e4e9cd4c01
commit d4be10dc2c
2 changed files with 70 additions and 18 deletions

View File

@ -25,6 +25,7 @@ class Scope:
# nested is true if the class could contain free variables,
# i.e. if it is nested within another function.
self.nested = None
self.generator = None
self.klass = None
if klass is not None:
for i in range(len(klass)):
@ -287,6 +288,27 @@ class SymbolVisitor:
name = name[:i]
scope.add_def(asname or name)
def visitGlobal(self, node, scope):
for name in node.names:
scope.add_global(name)
def visitAssign(self, node, scope):
"""Propagate assignment flag down to child nodes.
The Assign node doesn't itself contains the variables being
assigned to. Instead, the children in node.nodes are visited
with the assign flag set to true. When the names occur in
those nodes, they are marked as defs.
Some names that occur in an assignment target are not bound by
the assignment, e.g. a name occurring inside a slice. The
visitor handles these nodes specially; they do not propagate
the assign flag to their children.
"""
for n in node.nodes:
self.visit(n, scope, 1)
self.visit(node.expr, scope)
def visitAssName(self, node, scope, assign=1):
scope.add_def(node.name)
@ -297,6 +319,13 @@ class SymbolVisitor:
self.visit(node.expr, scope, 0)
for n in node.subs:
self.visit(n, scope, 0)
def visitSlice(self, node, scope, assign=0):
self.visit(node.expr, scope, assign)
if node.lower:
self.visit(node.lower, scope, 0)
if node.upper:
self.visit(node.upper, scope, 0)
def visitAugAssign(self, node, scope):
# If the LHS is a name, then this counts as assignment.
@ -306,15 +335,6 @@ class SymbolVisitor:
self.visit(node.node, scope, 1) # XXX worry about this
self.visit(node.expr, scope)
def visitAssign(self, node, scope):
for n in node.nodes:
self.visit(n, scope, 1)
self.visit(node.expr, scope)
def visitGlobal(self, node, scope):
for name in node.names:
scope.add_global(name)
# prune if statements if tests are false
_const_types = types.StringType, types.IntType, types.FloatType
@ -330,6 +350,12 @@ class SymbolVisitor:
if node.else_:
self.visit(node.else_, scope)
# a yield statement signals a generator
def visitYield(self, node, scope):
self.generator = 1
self.visit(node.value, scope)
def sort(l):
l = l[:]
l.sort()

View File

@ -25,6 +25,7 @@ class Scope:
# nested is true if the class could contain free variables,
# i.e. if it is nested within another function.
self.nested = None
self.generator = None
self.klass = None
if klass is not None:
for i in range(len(klass)):
@ -287,6 +288,27 @@ class SymbolVisitor:
name = name[:i]
scope.add_def(asname or name)
def visitGlobal(self, node, scope):
for name in node.names:
scope.add_global(name)
def visitAssign(self, node, scope):
"""Propagate assignment flag down to child nodes.
The Assign node doesn't itself contains the variables being
assigned to. Instead, the children in node.nodes are visited
with the assign flag set to true. When the names occur in
those nodes, they are marked as defs.
Some names that occur in an assignment target are not bound by
the assignment, e.g. a name occurring inside a slice. The
visitor handles these nodes specially; they do not propagate
the assign flag to their children.
"""
for n in node.nodes:
self.visit(n, scope, 1)
self.visit(node.expr, scope)
def visitAssName(self, node, scope, assign=1):
scope.add_def(node.name)
@ -297,6 +319,13 @@ class SymbolVisitor:
self.visit(node.expr, scope, 0)
for n in node.subs:
self.visit(n, scope, 0)
def visitSlice(self, node, scope, assign=0):
self.visit(node.expr, scope, assign)
if node.lower:
self.visit(node.lower, scope, 0)
if node.upper:
self.visit(node.upper, scope, 0)
def visitAugAssign(self, node, scope):
# If the LHS is a name, then this counts as assignment.
@ -306,15 +335,6 @@ class SymbolVisitor:
self.visit(node.node, scope, 1) # XXX worry about this
self.visit(node.expr, scope)
def visitAssign(self, node, scope):
for n in node.nodes:
self.visit(n, scope, 1)
self.visit(node.expr, scope)
def visitGlobal(self, node, scope):
for name in node.names:
scope.add_global(name)
# prune if statements if tests are false
_const_types = types.StringType, types.IntType, types.FloatType
@ -330,6 +350,12 @@ class SymbolVisitor:
if node.else_:
self.visit(node.else_, scope)
# a yield statement signals a generator
def visitYield(self, node, scope):
self.generator = 1
self.visit(node.value, scope)
def sort(l):
l = l[:]
l.sort()