diff --git a/lib/mako/ast.py b/lib/mako/ast.py
index f8ffc28b1a0529809166dc9d3dc00c1ca48ac38a..8c531407a96546bf18a31674a9b693a17f2b49d8 100644
--- a/lib/mako/ast.py
+++ b/lib/mako/ast.py
@@ -9,10 +9,16 @@ class PythonCode(object):
     """represents information about a string containing Python code"""
     def __init__(self, code, lineno, pos):
         self.code = code
+        
+        # represents all identifiers which are assigned to at some point in the code
         self.declared_identifiers = util.Set()
+        
+        # represents all identifiers which are referenced before their assignment, if any
         self.undeclared_identifiers = util.Set()
+        
+        # note that an identifier can be in both the undeclared and declared lists.
 
-        # note that using AST to parse instead of using code.co_varnames, code.co_names has several advantages:
+        # using AST to parse instead of using code.co_varnames, code.co_names has several advantages:
         # - we can locate an identifier as "undeclared" even if its declared later in the same block of code
         # - AST is less likely to break with version changes (for example, the behavior of co_names changed a little bit
         # in python version 2.5)
@@ -23,8 +29,19 @@ class PythonCode(object):
             
         class FindIdentifiers(object):
             def visitAssName(s, node, *args):
-                if node.name not in self.undeclared_identifiers:
-                    self.declared_identifiers.add(node.name)
+#                if node.name not in self.undeclared_identifiers:
+                self.declared_identifiers.add(node.name)
+            def visitAssign(s, node, *args):
+                # flip around the visiting of Assign so the expression gets evaluated first, 
+                # in the case of a clause like "x=x+5" (x is undeclared)
+                s.visit(node.expr, *args)
+                for n in node.nodes:
+                    s.visit(n, *args)
+            def visitFor(s, node, *args):
+                # flip around visit
+                s.visit(node.list, *args)
+                s.visit(node.assign, *args)
+                s.visit(node.body, *args)
             def visitTryExcept(s, node, *args):
                 for (decl, s2, s3) in node.handlers:
                     if decl is not None:
@@ -100,7 +117,7 @@ class FunctionDecl(object):
         if not hasattr(self, 'funcname'):
             raise exceptions.CompileException("Code '%s' is not a function declaration" % code, lineno, pos)
     def get_argument_expressions(self, include_defaults=True):
-        """return the argument declarations of this FunctionDecl as a printable list"""
+        """return the argument declarations of this FunctionDecl as a printable list."""
         namedecls = []
         defaults = [d for d in self.defaults]
         kwargs = self.kwargs
diff --git a/lib/mako/codegen.py b/lib/mako/codegen.py
index d1fda48f9641e8a19f07409a64278fae9af501c7..7b97b96e4c9409eab5486cc81011854201ab0c70 100644
--- a/lib/mako/codegen.py
+++ b/lib/mako/codegen.py
@@ -35,7 +35,6 @@ class Compiler(object):
             module_identifiers = module_identifiers.branch(n)
             printer.writeline("# SOURCE LINE %d" % n.lineno, is_comment=True)
             printer.write_indented_block(n.text)
-        
 
         main_identifiers = module_identifiers.branch(self.node)
         module_identifiers.toplevelcomponents = module_identifiers.toplevelcomponents.union(main_identifiers.toplevelcomponents)
@@ -48,7 +47,6 @@ class Compiler(object):
             _GenerateRenderMethod(printer, module_identifiers, node)
             
         return buf.getvalue()
-    
 
 class _GenerateRenderMethod(object):
     def __init__(self, printer, identifiers, node):
@@ -78,22 +76,32 @@ class _GenerateRenderMethod(object):
         printer.write("\n\n")
 
     def write_variable_declares(self, identifiers):
-        """write variable declarations at the top of a function."""
+        """write variable declarations at the top of a function.
+        
+        the variable declarations are generated based on the names that are referenced
+        in the function body before they are assigned.  names that are re-assigned 
+        from an enclosing scope are also declared as local variables so that the assignment 
+        can proceed.
+        
+        locally defined components (i.e. closures) are also generated, as well as 'stub' callables 
+        referencing top-level components which are referenced in the function body."""
+        
+        # collection of all components available to us in this scope
         comp_idents = dict([(c.name, c) for c in identifiers.components])
 
         # write explicit "context.get()" statements for variables that are already in the 
         # local namespace, that we are going to re-assign
-        print "WVD", identifiers
         to_write = identifiers.declared.intersection(identifiers.locally_declared)
         
         # write "context.get()" for all variables we are going to need that arent in the namespace yet
         to_write = to_write.union(identifiers.undeclared)
         
         # write closure functions for closures that we define right here
-        to_write = to_write.union(util.Set([c.name for c in identifiers.closurecomponents if c.parent is self.node]))
-        
+        to_write = to_write.union(util.Set([c.name for c in identifiers.closurecomponents]))
+
+        # remove identifiers that are declared in the argument signature of the callable
         to_write = to_write.difference(identifiers.argument_declared)
-        
+
         for ident in to_write:
             if ident in comp_idents:
                 comp = comp_idents[ident]
@@ -110,6 +118,7 @@ class _GenerateRenderMethod(object):
             self.last_source_line = node.lineno
 
     def write_component_decl(self, node, identifiers):
+        """write a locally-available callable referencing a top-level component"""
         funcname = node.function_decl.funcname
         namedecls = node.function_decl.get_argument_expressions()
         nameargs = node.function_decl.get_argument_expressions(include_defaults=False)
@@ -119,21 +128,20 @@ class _GenerateRenderMethod(object):
         self.printer.writeline(None)
         
     def write_inline_component(self, node, identifiers):
+        """write a locally-available component callable inside an enclosing component."""
         namedecls = node.function_decl.get_argument_expressions()
         self.printer.writeline("def %s(%s):" % (node.name, ",".join(namedecls)))
         
-        print "INLINE NAME", node.name
+        #print "INLINE NAME", node.name
         identifiers = identifiers.branch(node)
-        print "IDENTIFIERES", identifiers
+        
         # if we assign to variables in this closure, then we have to nest inside
         # of another callable so that the "context" variable is copied into the local scope
         make_closure = len(identifiers.locally_declared) > 0
         
         if make_closure:
             self.printer.writeline("def %s(%s):" % (node.name, ",".join(['context'] + namedecls)))
-            self.write_variable_declares(identifiers)
-        else:
-            self.write_variable_declares(identifiers)
+        self.write_variable_declares(identifiers)
 
         for n in node.nodes:
             n.accept_visitor(self)
@@ -172,7 +180,6 @@ class _GenerateRenderMethod(object):
         self.printer.writeline("def make_namespace():")
         export = []
         identifiers = self.identifiers #.branch(node)
-        print "NS IDENT", identifiers
         class NSComponentVisitor(object):
             def visitComponentTag(s, node):
                 self.write_inline_component(node, identifiers)
@@ -197,9 +204,10 @@ class _GenerateRenderMethod(object):
         pass
 
 class _Identifiers(object):
+    """tracks the status of identifier names as template code is rendered."""
     def __init__(self, node=None, parent=None):
         if parent is not None:
-            # things that have already been declared in the current namespace (i.e. names we can just use)
+            # things that have already been declared in an enclosing namespace (i.e. names we can just use)
             self.declared = util.Set(parent.declared).union([c.name for c in parent.closurecomponents]).union(parent.locally_declared)
             
             # top level components that are available
@@ -208,12 +216,14 @@ class _Identifiers(object):
             self.declared = util.Set()
             self.toplevelcomponents = util.Set()
         
-        # things within this level that are undeclared
+        # things within this level that are referenced before they are declared (e.g. assigned to)
         self.undeclared = util.Set()
         
-        # things that are declared locally
+        # things that are declared locally.  some of these things could be in the "undeclared"
+        # list as well if they are referenced before declared
         self.locally_declared = util.Set()
     
+        # things that are declared in the argument signature of the component callable
         self.argument_declared = util.Set()
         
         # closure components that are defined in this level
@@ -224,21 +234,21 @@ class _Identifiers(object):
             node.accept_visitor(self)
         
     def branch(self, node):
+        """create a new Identifiers for a new Node, with this Identifiers as the parent."""
         return _Identifiers(node, self)
         
     components = property(lambda s:s.toplevelcomponents.union(s.closurecomponents))
     
     def __repr__(self):
         return "Identifiers(%s, %s, %s, %s, %s)" % (repr(list(self.declared)), repr(list(self.locally_declared)), repr(list(self.undeclared)), repr([c.name for c in self.toplevelcomponents]), repr([c.name for c in self.closurecomponents]))
-    
         
     def check_declared(self, node):
-        for ident in node.declared_identifiers():
-            self.locally_declared.add(ident)
+        """update the state of this Identifiers with the undeclared and declared identifiers of the given node."""
         for ident in node.undeclared_identifiers():
-            print "UNDECL IDENT IN NODE", node, ident
             if ident != 'context' and ident not in self.declared.union(self.locally_declared):
                 self.undeclared.add(ident)
+        for ident in node.declared_identifiers():
+            self.locally_declared.add(ident)
                 
     def visitExpression(self, node):
         self.check_declared(node)
@@ -254,6 +264,7 @@ class _Identifiers(object):
             self.closurecomponents.add(node)
         for ident in node.declared_identifiers():
             self.argument_declared.add(ident)
+        # visit components only one level deep
         if node is self.node:
             for n in node.nodes:
                 n.accept_visitor(self)
diff --git a/lib/mako/lexer.py b/lib/mako/lexer.py
index 2dfa5d1f3d4902e2e23f54e6d18ec295fedff664..2cae84705902d514752858ba430c13c2fc3c9d3c 100644
--- a/lib/mako/lexer.py
+++ b/lib/mako/lexer.py
@@ -61,8 +61,7 @@ class Lexer(object):
                 self.control_line.append(node)
             elif len(self.control_line) and not self.control_line[-1].is_ternary(node.keyword):
                 raise exceptions.SyntaxException("Keyword '%s' not a legal ternary for keyword '%s'" % (node.keyword, self.control_line[-1].keyword), self.matched_lineno, self.matched_charpos)
-                
-                    
+
     def parse(self):
         length = len(self.text)
         while (True):
diff --git a/lib/mako/parsetree.py b/lib/mako/parsetree.py
index 23936b900177a8843144d0c19e8b6f40392e07e7..849b6e9c038774a7b1aa0b1e2ebe624da2df7559 100644
--- a/lib/mako/parsetree.py
+++ b/lib/mako/parsetree.py
@@ -204,12 +204,12 @@ class Tag(Node):
 class IncludeTag(Tag):
     __keyword__ = 'include'
     def __init__(self, keyword, attributes, **kwargs):
-        super(IncludeTag, self).__init__(keyword, attributes, util.Set(['file', 'import']), util.Set([]), util.Set(['file']), **kwargs)
+        super(IncludeTag, self).__init__(keyword, attributes, ('file', 'import'), (), ('file',), **kwargs)
     
 class NamespaceTag(Tag):
     __keyword__ = 'namespace'
     def __init__(self, keyword, attributes, **kwargs):
-        super(NamespaceTag, self).__init__(keyword, attributes, util.Set(['file']), util.Set(['name']), util.Set(['name']), **kwargs)
+        super(NamespaceTag, self).__init__(keyword, attributes, ('file',), ('name',), ('name',), **kwargs)
         self.name = attributes['name']
     def declared_identifiers(self):
         return [self.name]
@@ -219,7 +219,7 @@ class NamespaceTag(Tag):
 class ComponentTag(Tag):
     __keyword__ = 'component'
     def __init__(self, keyword, attributes, **kwargs):
-        super(ComponentTag, self).__init__(keyword, attributes, util.Set([]), util.Set(['name']), util.Set(['name']), **kwargs)
+        super(ComponentTag, self).__init__(keyword, attributes, (), ('name',), ('name',), **kwargs)
         name = attributes['name']
         if re.match(r'^[\w_]+$',name):
             name = name + "()"
@@ -236,15 +236,15 @@ class ComponentTag(Tag):
 class CallTag(Tag):
     __keyword__ = 'call'
     def __init__(self, keyword, attributes, **kwargs):
-        super(CallTag, self).__init__(keyword, attributes, util.Set([]), util.Set(['expr']), util.Set(['expr']), **kwargs)
+        super(CallTag, self).__init__(keyword, attributes, (), ('expr',), ('expr',), **kwargs)
 
 class InheritTag(Tag):
     __keyword__ = 'inherit'
     def __init__(self, keyword, attributes, **kwargs):
-        super(InheritTag, self).__init__(keyword, attributes, util.Set(['file']), util.Set([]), util.Set(['file']), **kwargs)
+        super(InheritTag, self).__init__(keyword, attributes, ('file',), (), ('file',), **kwargs)
 
 class PageTag(Tag):
     __keyword__ = 'page'
     def __init__(self, keyword, attributes, **kwargs):
-        super(PageTag, self).__init__(keyword, attributes, util.Set([]), util.Set([]), util.Set([]), **kwargs)
+        super(PageTag, self).__init__(keyword, attributes, (), (), (), **kwargs)
     
\ No newline at end of file
diff --git a/lib/mako/pygen.py b/lib/mako/pygen.py
index 1cd0d0dfae569c7fbe72e6b3ce189a60b5f38865..825439601f43b26508c0555af77c6b5d908a4de5 100644
--- a/lib/mako/pygen.py
+++ b/lib/mako/pygen.py
@@ -197,6 +197,7 @@ class PythonPrinter(object):
 
 
 def adjust_whitespace(text):
+    """remove the left-whitespace margin of a block of Python code."""
     state = [False, False]
     (backslashed, triplequoted) = (0, 1)
     def in_multi_line(line):
diff --git a/lib/mako/runtime.py b/lib/mako/runtime.py
index 76cb4b4c84260e4dd1c34056758271cc6c7e88c4..f50632a5b562625d1546ba8d942ce162a84784ef 100644
--- a/lib/mako/runtime.py
+++ b/lib/mako/runtime.py
@@ -15,6 +15,8 @@ class Context(object):
     def write(self, string):
         self.buffer.write(string)
     def update(self, **args):
+        """produce a copy of this Context, updating the argument dictionary
+        with the given keyword arguments."""
         x = self.data.copy()
         x.update(args)
         c = Context(self.buffer, **x)
diff --git a/test/ast.py b/test/ast.py
index f418d611780fd7ad656a7b08b6b0829ec88edac2..5a7da59ee951173644aec73d733e500f33e70305 100644
--- a/test/ast.py
+++ b/test/ast.py
@@ -24,7 +24,7 @@ print "hello world, ", a, b
 print "Another expr", c
 """
         parsed = ast.PythonCode(code, 0, 0)
-        assert parsed.declared_identifiers == util.Set(['a','b','c', 'g', 'h', 'i', 'u', 'k', 'j', 'gh', 'lar'])
+        assert parsed.declared_identifiers == util.Set(['a','b','c', 'g', 'h', 'i', 'u', 'k', 'j', 'gh', 'lar', 'x'])
         assert parsed.undeclared_identifiers == util.Set(['x', 'q', 'foo', 'gah', 'blah'])
     
         parsed = ast.PythonCode("x + 5 * (y-z)", 0, 0)
@@ -45,6 +45,19 @@ for x in data:
         assert parsed.undeclared_identifiers == util.Set(['get_data'])
         assert parsed.declared_identifiers == util.Set(['result', 'data', 'x', 'hoho', 'foobar', 'foo', 'yaya'])
 
+    def test_locate_identifiers_3(self):
+        """test that combination assignment/expressions of the same identifier log the ident as 'undeclared'"""
+        code = """
+x = x + 5
+for y in range(1, y):
+    print "hi"
+[z for z in range(1, z)]
+(q for q in range (1, q))
+"""
+        parsed = ast.PythonCode(code, 0, 0)
+        print parsed.undeclared_identifiers
+        assert parsed.undeclared_identifiers == util.Set(['x', 'y', 'z', 'q'])
+        
     def test_no_global_imports(self):
         code = """
 from foo import *
diff --git a/test/template.py b/test/template.py
index 38e3b0e6492ae85882f782e90d9aec0181b8a502..8dd2f3e4420203b7848a758e9e574b16093499f9 100644
--- a/test/template.py
+++ b/test/template.py
@@ -99,6 +99,30 @@ im c
         result = re.sub(r'[\s\n]+', ' ', result).strip()
         assert result == "y is None y is 7"
 
+    def test_local_names_3(self):
+        """test in place assignment/undeclared variable combinations
+        
+        
+        i.e. things like 'x=x+1', x is declared and undeclared at the same time"""
+        template = Template("""
+        hi
+    	<%component name="a">
+    	    y is ${y}
+
+            <%
+                x = x + y
+                a = 3
+            %>
+            
+            x is ${x}
+    	</%component>
+
+    	${a()}
+    """)
+        result = template.render(x=5, y=10)
+        result = re.sub(r'[\s\n]+', ' ', result).strip()
+        assert result == "hi y is 10 x is 15"
+
 class NestedComponentTest(unittest.TestCase):
     def test_nested_component(self):
         template = """