docs: def function_scoping(self, node, frame, children=None,
                           find_special=True):
          """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.
          """
          # we have to iterate twice over it, make sure that works
          if children is None:
              children = node.iter_child_nodes()
          children = list(children)
          func_frame = frame.inner()
          func_frame.inspect(children, hard_scope=True)
  
          # variables that are undeclared (accessed before declaration) and
          # declared locally *and* part of an outside scope raise a template
          # assertion error. Reason: we can't generate reasonable code from
          # it without aliasing all the variables.
          # this could be fixed in Python 3 where we have the nonlocal
          # keyword or if we switch to bytecode generation
          overriden_closure_vars = (
              func_frame.identifiers.undeclared &
              func_frame.identifiers.declared &
              (func_frame.identifiers.declared_locally |
               func_frame.identifiers.declared_parameter)
          )
          if overriden_closure_vars:
              self.fail('It\'s not possible to set and access variables '
                        'derived from an outer scope! (affects: %s)' %
                        ', '.join(sorted(overriden_closure_vars)), node.lineno)
  
          # remove variables from a closure from the frame's undeclared
          # identifiers.
          func_frame.identifiers.undeclared -= (
              func_frame.identifiers.undeclared &
              func_frame.identifiers.declared
          )
  
          # no special variables for this scope, abort early
          if not find_special:
              return func_frame
  
          func_frame.accesses_kwargs = False
          func_frame.accesses_varargs = False
          func_frame.accesses_caller = False
          func_frame.arguments = args = ['l_' + x.name for x in node.args]
  
          undeclared = find_undeclared(children, ('caller', 'kwargs', 'varargs'))
  
          if 'caller' in undeclared:
              func_frame.accesses_caller = True
              func_frame.identifiers.add_special('caller')
              args.append('l_caller')
          if 'kwargs' in undeclared:
              func_frame.accesses_kwargs = True
              func_frame.identifiers.add_special('kwargs')
              args.append('l_kwargs')
          if 'varargs' in undeclared:
              func_frame.accesses_varargs = True
              func_frame.identifiers.add_special('varargs')
              args.append('l_varargs')
          return func_frame