added globals

--HG--
branch : trunk
diff --git a/jinja2/compiler.py b/jinja2/compiler.py
index 3c2347d..bf72963 100644
--- a/jinja2/compiler.py
+++ b/jinja2/compiler.py
@@ -39,8 +39,7 @@
 
 def generate(node, environment, filename, stream=None):
     """Generate the python source for a node tree."""
-    is_child = node.find(nodes.Extends) is not None
-    generator = CodeGenerator(environment, is_child, filename, stream)
+    generator = CodeGenerator(environment, filename, stream)
     generator.visit(node)
     if stream is None:
         return generator.stream.getvalue()
@@ -114,16 +113,31 @@
 
     def __init__(self, parent=None):
         self.identifiers = Identifiers()
+
         # a toplevel frame is the root + soft frames such as if conditions.
         self.toplevel = False
+
         # the root frame is basically just the outermost frame, so no if
         # conditions.  This information is used to optimize inheritance
         # situations.
         self.rootlevel = False
-        self.parent = parent
+
+        # inside some tags we are using a buffer rather than yield statements.
+        # this for example affects {% filter %} or {% macro %}.  If a frame
+        # is buffered this variable points to the name of the list used as
+        # buffer.
         self.buffer = None
+
+        # if a frame has name_overrides, all read access to a name in this
+        # dict is redirected to a string expression.
         self.name_overrides = {}
+
+        # the name of the block we're in, otherwise None.
         self.block = parent and parent.block or None
+
+        # the parent of this frame
+        self.parent = parent
+
         if parent is not None:
             self.identifiers.declared.update(
                 parent.identifiers.declared |
@@ -214,33 +228,61 @@
 
 class CodeGenerator(NodeVisitor):
 
-    def __init__(self, environment, is_child, filename, stream=None):
+    def __init__(self, environment, filename, stream=None):
         if stream is None:
             stream = StringIO()
         self.environment = environment
-        self.is_child = is_child
         self.filename = filename
         self.stream = stream
+
+        # a registry for all blocks.  Because blocks are moved out
+        # into the global python scope they are registered here
         self.blocks = {}
-        self.indentation = 0
-        self.new_lines = 0
-        self.last_identifier = 0
+
+        # the number of extends statements so far
         self.extends_so_far = 0
+
+        # some templates have a rootlevel extends.  In this case we
+        # can safely assume that we're a child template and do some
+        # more optimizations.
         self.has_known_extends = False
+
+        # the number of new lines before the next write()
+        self._new_lines = 0
+
+        # the line number of the last written statement
         self._last_line = 0
+
+        # true if nothing was written so far.
         self._first_write = True
 
+        # used by the `temporary_identifier` method to get new
+        # unique, temporary identifier
+        self._last_identifier = 0
+
+        # the current indentation
+        self._indentation = 0
+
     def temporary_identifier(self):
-        self.last_identifier += 1
-        return 't%d' % self.last_identifier
+        """Get a new unique identifier."""
+        self._last_identifier += 1
+        return 't%d' % self._last_identifier
 
     def indent(self):
-        self.indentation += 1
+        """Indent by one."""
+        self._indentation += 1
 
     def outdent(self, step=1):
-        self.indentation -= step
+        """Outdent by step."""
+        self._indentation -= step
 
     def blockvisit(self, nodes, frame, indent=True, force_generator=True):
+        """Visit a list of nodes as block in a frame.  Per default the
+        code is indented, but this can be disabled by setting the indent
+        parameter to False.  If the current frame is no buffer a dummy
+        ``if 0: yield None`` is written automatically unless the
+        force_generator parameter is set to False.
+        """
         if indent:
             self.indent()
         if frame.buffer is None and force_generator:
@@ -254,26 +296,36 @@
             self.outdent()
 
     def write(self, x):
-        if self.new_lines:
+        """Write a string into the output stream."""
+        if self._new_lines:
             if not self._first_write:
-                self.stream.write('\n' * self.new_lines)
+                self.stream.write('\n' * self._new_lines)
             self._first_write = False
-            self.stream.write('    ' * self.indentation)
-            self.new_lines = 0
+            self.stream.write('    ' * self._indentation)
+            self._new_lines = 0
         self.stream.write(x)
 
     def writeline(self, x, node=None, extra=0):
+        """Combination of newline and write."""
         self.newline(node, extra)
         self.write(x)
 
     def newline(self, node=None, extra=0):
-        self.new_lines = max(self.new_lines, 1 + extra)
+        """Add one or more newlines before the next write."""
+        self._new_lines = max(self._new_lines, 1 + extra)
         if node is not None and node.lineno != self._last_line:
             self.write('# line: %s' % node.lineno)
-            self.new_lines = 1
+            self._new_lines = 1
             self._last_line = node.lineno
 
     def signature(self, node, frame, have_comma=True, extra_kwargs=None):
+        """Writes a function call to the stream for the current node.
+        Per default it will write a leading comma but this can be
+        disabled by setting have_comma to False.  If extra_kwargs is
+        given it must be a string that represents a single keyword
+        argument call that is inserted at the end of the regular
+        keyword argument calls.
+        """
         have_comma = have_comma and [True] or []
         def touch_comma():
             if have_comma:
@@ -300,6 +352,10 @@
             self.visit(node.dyn_kwargs, frame)
 
     def pull_locals(self, frame, indent=True):
+        """Pull all the references identifiers into the local scope.
+        This affects regular names, filters and tests.  If indent is
+        set to False, no automatic indentation will take place.
+        """
         if indent:
             self.indent()
         for name in frame.identifiers.undeclared:
@@ -312,6 +368,10 @@
             self.outdent()
 
     def collect_shadowed(self, frame):
+        """This function returns all the shadowed variables in a dict
+        in the form name: alias and will write the required assignments
+        into the current scope.  No indentation takes place.
+        """
         # make sure we "backup" overridden, local identifiers
         # TODO: we should probably optimize this and check if the
         # identifier is in use afterwards.
@@ -322,6 +382,17 @@
         return aliases
 
     def function_scoping(self, node, frame):
+        """In Jinja a few statements require the help of anonymous
+        functions.  Those are currently macros and call blocks and in
+        the future also recursive loops.  As there is currently
+        technical limitation that doesn't allow reading and writing a
+        variable in a scope where the initial value is coming from an
+        outer scope, this function tries to fall back with a common
+        error message.  Additionally the frame passed is modified so
+        that the argumetns are collected and callers are looked up.
+
+        This will return the modified frame.
+        """
         func_frame = frame.inner()
         func_frame.inspect(node.iter_child_nodes(), hard_scope=True)