| Index: third_party/jinja2/compiler.py
|
| diff --git a/third_party/jinja2/compiler.py b/third_party/jinja2/compiler.py
|
| index 75a60b8d2d6b326d6248b64a0b74538316d4f82c..fad007b596f66fc090d155bb97a8fc5967749608 100644
|
| --- a/third_party/jinja2/compiler.py
|
| +++ b/third_party/jinja2/compiler.py
|
| @@ -16,7 +16,7 @@ from jinja2.nodes import EvalContext
|
| from jinja2.visitor import NodeVisitor
|
| from jinja2.exceptions import TemplateAssertionError
|
| from jinja2.utils import Markup, concat, escape
|
| -from jinja2._compat import range_type, next, text_type, string_types, \
|
| +from jinja2._compat import range_type, text_type, string_types, \
|
| iteritems, NativeStringIO, imap
|
|
|
|
|
| @@ -57,7 +57,8 @@ def generate(node, environment, name, filename, stream=None,
|
| """Generate the python source for a node tree."""
|
| if not isinstance(node, nodes.Template):
|
| raise TypeError('Can\'t compile non template nodes')
|
| - generator = CodeGenerator(environment, name, filename, stream, defer_init)
|
| + generator = environment.code_generator_class(environment, name, filename,
|
| + stream, defer_init)
|
| generator.visit(node)
|
| if stream is None:
|
| return generator.stream.getvalue()
|
| @@ -347,6 +348,9 @@ class FrameIdentifierVisitor(NodeVisitor):
|
| def visit_FilterBlock(self, node):
|
| self.visit(node.filter)
|
|
|
| + def visit_AssignBlock(self, node):
|
| + """Stop visiting at block assigns."""
|
| +
|
| def visit_Scope(self, node):
|
| """Stop visiting at scopes."""
|
|
|
| @@ -1215,8 +1219,17 @@ class CodeGenerator(NodeVisitor):
|
| if self.has_known_extends and frame.require_output_check:
|
| return
|
|
|
| + allow_constant_finalize = True
|
| if self.environment.finalize:
|
| - finalize = lambda x: text_type(self.environment.finalize(x))
|
| + func = self.environment.finalize
|
| + if getattr(func, 'contextfunction', False) or \
|
| + getattr(func, 'evalcontextfunction', False):
|
| + allow_constant_finalize = False
|
| + elif getattr(func, 'environmentfunction', False):
|
| + finalize = lambda x: text_type(
|
| + self.environment.finalize(self.environment, x))
|
| + else:
|
| + finalize = lambda x: text_type(self.environment.finalize(x))
|
| else:
|
| finalize = text_type
|
|
|
| @@ -1232,6 +1245,8 @@ class CodeGenerator(NodeVisitor):
|
| body = []
|
| for child in node.nodes:
|
| try:
|
| + if not allow_constant_finalize:
|
| + raise nodes.Impossible()
|
| const = child.as_const(frame.eval_ctx)
|
| except nodes.Impossible:
|
| body.append(child)
|
| @@ -1287,6 +1302,9 @@ class CodeGenerator(NodeVisitor):
|
| self.write('to_string(')
|
| if self.environment.finalize is not None:
|
| self.write('environment.finalize(')
|
| + if getattr(self.environment.finalize,
|
| + "contextfunction", False):
|
| + self.write('context, ')
|
| close += 1
|
| self.visit(item, frame)
|
| self.write(')' * close)
|
| @@ -1309,7 +1327,6 @@ class CodeGenerator(NodeVisitor):
|
| arguments.append(item)
|
| self.writeline('yield ')
|
| self.write(repr(concat(format)) + ' % (')
|
| - idx = -1
|
| self.indent()
|
| for argument in arguments:
|
| self.newline(argument)
|
| @@ -1323,6 +1340,15 @@ class CodeGenerator(NodeVisitor):
|
| close += 1
|
| if self.environment.finalize is not None:
|
| self.write('environment.finalize(')
|
| + if getattr(self.environment.finalize,
|
| + 'contextfunction', False):
|
| + self.write('context, ')
|
| + elif getattr(self.environment.finalize,
|
| + 'evalcontextfunction', False):
|
| + self.write('context.eval_ctx, ')
|
| + elif getattr(self.environment.finalize,
|
| + 'environmentfunction', False):
|
| + self.write('environment, ')
|
| close += 1
|
| self.visit(argument, frame)
|
| self.write(')' * close + ', ')
|
| @@ -1332,42 +1358,62 @@ class CodeGenerator(NodeVisitor):
|
| if outdent_later:
|
| self.outdent()
|
|
|
| - def visit_Assign(self, node, frame):
|
| - self.newline(node)
|
| + def make_assignment_frame(self, frame):
|
| # toplevel assignments however go into the local namespace and
|
| # the current template's context. We create a copy of the frame
|
| # here and add a set so that the Name visitor can add the assigned
|
| # names here.
|
| - if frame.toplevel:
|
| - assignment_frame = frame.copy()
|
| - assignment_frame.toplevel_assignments = set()
|
| + if not frame.toplevel:
|
| + return frame
|
| + assignment_frame = frame.copy()
|
| + assignment_frame.toplevel_assignments = set()
|
| + return assignment_frame
|
| +
|
| + def export_assigned_vars(self, frame, assignment_frame):
|
| + if not frame.toplevel:
|
| + return
|
| + public_names = [x for x in assignment_frame.toplevel_assignments
|
| + if not x.startswith('_')]
|
| + if len(assignment_frame.toplevel_assignments) == 1:
|
| + name = next(iter(assignment_frame.toplevel_assignments))
|
| + self.writeline('context.vars[%r] = l_%s' % (name, name))
|
| else:
|
| - assignment_frame = frame
|
| + self.writeline('context.vars.update({')
|
| + for idx, name in enumerate(assignment_frame.toplevel_assignments):
|
| + if idx:
|
| + self.write(', ')
|
| + self.write('%r: l_%s' % (name, name))
|
| + self.write('})')
|
| + if public_names:
|
| + if len(public_names) == 1:
|
| + self.writeline('context.exported_vars.add(%r)' %
|
| + public_names[0])
|
| + else:
|
| + self.writeline('context.exported_vars.update((%s))' %
|
| + ', '.join(imap(repr, public_names)))
|
| +
|
| + def visit_Assign(self, node, frame):
|
| + self.newline(node)
|
| + assignment_frame = self.make_assignment_frame(frame)
|
| self.visit(node.target, assignment_frame)
|
| self.write(' = ')
|
| self.visit(node.node, frame)
|
| -
|
| - # make sure toplevel assignments are added to the context.
|
| - if frame.toplevel:
|
| - public_names = [x for x in assignment_frame.toplevel_assignments
|
| - if not x.startswith('_')]
|
| - if len(assignment_frame.toplevel_assignments) == 1:
|
| - name = next(iter(assignment_frame.toplevel_assignments))
|
| - self.writeline('context.vars[%r] = l_%s' % (name, name))
|
| - else:
|
| - self.writeline('context.vars.update({')
|
| - for idx, name in enumerate(assignment_frame.toplevel_assignments):
|
| - if idx:
|
| - self.write(', ')
|
| - self.write('%r: l_%s' % (name, name))
|
| - self.write('})')
|
| - if public_names:
|
| - if len(public_names) == 1:
|
| - self.writeline('context.exported_vars.add(%r)' %
|
| - public_names[0])
|
| - else:
|
| - self.writeline('context.exported_vars.update((%s))' %
|
| - ', '.join(imap(repr, public_names)))
|
| + self.export_assigned_vars(frame, assignment_frame)
|
| +
|
| + def visit_AssignBlock(self, node, frame):
|
| + block_frame = frame.inner()
|
| + block_frame.inspect(node.body)
|
| + aliases = self.push_scope(block_frame)
|
| + self.pull_locals(block_frame)
|
| + self.buffer(block_frame)
|
| + self.blockvisit(node.body, block_frame)
|
| + self.pop_scope(aliases, block_frame)
|
| +
|
| + assignment_frame = self.make_assignment_frame(frame)
|
| + self.newline(node)
|
| + self.visit(node.target, assignment_frame)
|
| + self.write(' = concat(%s)' % block_frame.buffer)
|
| + self.export_assigned_vars(frame, assignment_frame)
|
|
|
| # -- Expression Visitors
|
|
|
|
|