added support for new call statement

--HG--
branch : trunk
diff --git a/jinja2/compiler.py b/jinja2/compiler.py
index 63a140f..83e07e6 100644
--- a/jinja2/compiler.py
+++ b/jinja2/compiler.py
@@ -258,7 +258,7 @@
             self.new_lines = 1
             self._last_line = node.lineno
 
-    def signature(self, node, frame, have_comma=True):
+    def signature(self, node, frame, have_comma=True, extra_kwargs=None):
         have_comma = have_comma and [True] or []
         def touch_comma():
             if have_comma:
@@ -272,11 +272,16 @@
         for kwarg in node.kwargs:
             touch_comma()
             self.visit(kwarg, frame)
+        if extra_kwargs is not None:
+            touch_comma()
+            self.write(extra_kwargs)
         if node.dyn_args:
             touch_comma()
+            self.write('*')
             self.visit(node.dyn_args, frame)
         if node.dyn_kwargs:
             touch_comma()
+            self.write('**')
             self.visit(node.dyn_kwargs, frame)
 
     def pull_locals(self, frame, no_indent=False):
@@ -291,6 +296,48 @@
         if not no_indent:
             self.outdent()
 
+    def function_scoping(self, node, frame):
+        func_frame = frame.inner()
+        func_frame.inspect(node.iter_child_nodes(), 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.  XXX: alias them ^^
+        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:
+            vars = ', '.join(sorted(overriden_closure_vars))
+            raise TemplateAssertionError('It\'s not possible to set and '
+                                         'access variables derived from '
+                                         'an outer scope! (affects: %s' %
+                                         vars, node.lineno, self.filename)
+
+        # remove variables from a closure from the frame's undeclared
+        # identifiers.
+        func_frame.identifiers.undeclared -= (
+            func_frame.identifiers.undeclared &
+            func_frame.identifiers.declared
+        )
+
+        func_frame.accesses_arguments = False
+        func_frame.accesses_caller = False
+        func_frame.arguments = args = ['l_' + x.name for x in node.args]
+
+        if 'arguments' in func_frame.identifiers.undeclared:
+            func_frame.accesses_arguments = True
+            func_frame.identifiers.add_special('arguments')
+            args.append('l_arguments')
+        if 'caller' in func_frame.identifiers.undeclared:
+            func_frame.accesses_caller = True
+            func_frame.identifiers.add_special('caller')
+            args.append('l_caller')
+        return func_frame
+
     # -- Visitors
 
     def visit_Template(self, node, frame=None):
@@ -489,45 +536,11 @@
             self.blockvisit(node.else_, if_frame)
 
     def visit_Macro(self, node, frame):
-        macro_frame = frame.inner()
-        macro_frame.inspect(node.iter_child_nodes(), 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.  XXX: alias them ^^
-        overriden_closure_vars = (
-            macro_frame.identifiers.undeclared &
-            macro_frame.identifiers.declared &
-            (macro_frame.identifiers.declared_locally |
-             macro_frame.identifiers.declared_parameter)
-        )
-        if overriden_closure_vars:
-            vars = ', '.join(sorted(overriden_closure_vars))
-            raise TemplateAssertionError('It\'s not possible to set and '
-                                         'access variables derived from '
-                                         'an outer scope! (affects: %s' %
-                                         vars, node.lineno, self.filename)
-
-        # remove variables from a closure from the frame's undeclared
-        # identifiers.
-        macro_frame.identifiers.undeclared -= (
-            macro_frame.identifiers.undeclared &
-            macro_frame.identifiers.declared
-        )
-
-        args = ['l_' + x.name for x in node.args]
-        if 'arguments' in macro_frame.identifiers.undeclared:
-            accesses_arguments = True
-            args.append('l_arguments')
-        else:
-            accesses_arguments = False
+        macro_frame = self.function_scoping(node, frame)
+        args = macro_frame.arguments
         self.writeline('def macro(%s):' % ', '.join(args), node)
-        self.indent()
-        self.writeline('if 0: yield None')
-        self.outdent()
         self.pull_locals(macro_frame)
-        self.blockvisit(node.body, macro_frame)
+        self.blockvisit(node.body, macro_frame, True)
         self.newline()
         if frame.toplevel:
             self.write('context[%r] = ' % node.name)
@@ -539,7 +552,26 @@
         for arg in node.defaults:
             self.visit(arg)
             self.write(', ')
-        self.write('), %r)' % accesses_arguments)
+        self.write('), %r, %r)' % (
+            macro_frame.accesses_arguments,
+            macro_frame.accesses_caller
+        ))
+
+    def visit_CallBlock(self, node, frame):
+        call_frame = self.function_scoping(node, frame)
+        args = call_frame.arguments
+        self.writeline('def call(%s):' % ', '.join(args), node)
+        self.blockvisit(node.body, call_frame, node)
+        arg_tuple = ', '.join(repr(x.name) for x in node.args)
+        if len(node.args) == 1:
+            arg_tuple += ','
+        self.writeline('caller = Macro(call, None, (%s), (' % arg_tuple)
+        for arg in node.defaults:
+            self.visit(arg)
+            self.write(', ')
+        self.write('), %r, False)' % call_frame.accesses_arguments)
+        self.writeline('yield ', node)
+        self.visit_Call(node.call, call_frame, extra_kwargs='caller=caller')
 
     def visit_ExprStmt(self, node, frame):
         self.newline(node)
@@ -770,10 +802,10 @@
         self.signature(node, frame)
         self.write(')')
 
-    def visit_Call(self, node, frame):
+    def visit_Call(self, node, frame, extra_kwargs=None):
         self.visit(node.node, frame)
         self.write('(')
-        self.signature(node, frame, False)
+        self.signature(node, frame, False, extra_kwargs)
         self.write(')')
 
     def visit_Keyword(self, node, frame):