| OLD | NEW |
| 1 # -*- coding: utf-8 -*- | 1 # -*- coding: utf-8 -*- |
| 2 """ | 2 """ |
| 3 jinja2.compiler | 3 jinja2.compiler |
| 4 ~~~~~~~~~~~~~~~ | 4 ~~~~~~~~~~~~~~~ |
| 5 | 5 |
| 6 Compiles nodes into python code. | 6 Compiles nodes into python code. |
| 7 | 7 |
| 8 :copyright: (c) 2010 by the Jinja Team. | 8 :copyright: (c) 2010 by the Jinja Team. |
| 9 :license: BSD, see LICENSE for more details. | 9 :license: BSD, see LICENSE for more details. |
| 10 """ | 10 """ |
| 11 from cStringIO import StringIO | |
| 12 from itertools import chain | 11 from itertools import chain |
| 13 from copy import deepcopy | 12 from copy import deepcopy |
| 13 from keyword import iskeyword as is_python_keyword |
| 14 from jinja2 import nodes | 14 from jinja2 import nodes |
| 15 from jinja2.nodes import EvalContext | 15 from jinja2.nodes import EvalContext |
| 16 from jinja2.visitor import NodeVisitor | 16 from jinja2.visitor import NodeVisitor |
| 17 from jinja2.exceptions import TemplateAssertionError | 17 from jinja2.exceptions import TemplateAssertionError |
| 18 from jinja2.utils import Markup, concat, escape, is_python_keyword, next | 18 from jinja2.utils import Markup, concat, escape |
| 19 from jinja2._compat import range_type, next, text_type, string_types, \ |
| 20 iteritems, NativeStringIO, imap |
| 19 | 21 |
| 20 | 22 |
| 21 operators = { | 23 operators = { |
| 22 'eq': '==', | 24 'eq': '==', |
| 23 'ne': '!=', | 25 'ne': '!=', |
| 24 'gt': '>', | 26 'gt': '>', |
| 25 'gteq': '>=', | 27 'gteq': '>=', |
| 26 'lt': '<', | 28 'lt': '<', |
| 27 'lteq': '<=', | 29 'lteq': '<=', |
| 28 'in': 'in', | 30 'in': 'in', |
| 29 'notin': 'not in' | 31 'notin': 'not in' |
| 30 } | 32 } |
| 31 | 33 |
| 32 try: | |
| 33 exec '(0 if 0 else 0)' | |
| 34 except SyntaxError: | |
| 35 have_condexpr = False | |
| 36 else: | |
| 37 have_condexpr = True | |
| 38 | |
| 39 | |
| 40 # what method to iterate over items do we want to use for dict iteration | 34 # what method to iterate over items do we want to use for dict iteration |
| 41 # in generated code? on 2.x let's go with iteritems, on 3.x with items | 35 # in generated code? on 2.x let's go with iteritems, on 3.x with items |
| 42 if hasattr(dict, 'iteritems'): | 36 if hasattr(dict, 'iteritems'): |
| 43 dict_item_iter = 'iteritems' | 37 dict_item_iter = 'iteritems' |
| 44 else: | 38 else: |
| 45 dict_item_iter = 'items' | 39 dict_item_iter = 'items' |
| 46 | 40 |
| 47 | 41 |
| 48 # does if 0: dummy(x) get us x into the scope? | 42 # does if 0: dummy(x) get us x into the scope? |
| 49 def unoptimize_before_dead_code(): | 43 def unoptimize_before_dead_code(): |
| 50 x = 42 | 44 x = 42 |
| 51 def f(): | 45 def f(): |
| 52 if 0: dummy(x) | 46 if 0: dummy(x) |
| 53 return f | 47 return f |
| 54 unoptimize_before_dead_code = bool(unoptimize_before_dead_code().func_closure) | 48 |
| 49 # The getattr is necessary for pypy which does not set this attribute if |
| 50 # no closure is on the function |
| 51 unoptimize_before_dead_code = bool( |
| 52 getattr(unoptimize_before_dead_code(), '__closure__', None)) |
| 55 | 53 |
| 56 | 54 |
| 57 def generate(node, environment, name, filename, stream=None, | 55 def generate(node, environment, name, filename, stream=None, |
| 58 defer_init=False): | 56 defer_init=False): |
| 59 """Generate the python source for a node tree.""" | 57 """Generate the python source for a node tree.""" |
| 60 if not isinstance(node, nodes.Template): | 58 if not isinstance(node, nodes.Template): |
| 61 raise TypeError('Can\'t compile non template nodes') | 59 raise TypeError('Can\'t compile non template nodes') |
| 62 generator = CodeGenerator(environment, name, filename, stream, defer_init) | 60 generator = CodeGenerator(environment, name, filename, stream, defer_init) |
| 63 generator.visit(node) | 61 generator.visit(node) |
| 64 if stream is None: | 62 if stream is None: |
| 65 return generator.stream.getvalue() | 63 return generator.stream.getvalue() |
| 66 | 64 |
| 67 | 65 |
| 68 def has_safe_repr(value): | 66 def has_safe_repr(value): |
| 69 """Does the node have a safe representation?""" | 67 """Does the node have a safe representation?""" |
| 70 if value is None or value is NotImplemented or value is Ellipsis: | 68 if value is None or value is NotImplemented or value is Ellipsis: |
| 71 return True | 69 return True |
| 72 if isinstance(value, (bool, int, long, float, complex, basestring, | 70 if isinstance(value, (bool, int, float, complex, range_type, |
| 73 xrange, Markup)): | 71 Markup) + string_types): |
| 74 return True | 72 return True |
| 75 if isinstance(value, (tuple, list, set, frozenset)): | 73 if isinstance(value, (tuple, list, set, frozenset)): |
| 76 for item in value: | 74 for item in value: |
| 77 if not has_safe_repr(item): | 75 if not has_safe_repr(item): |
| 78 return False | 76 return False |
| 79 return True | 77 return True |
| 80 elif isinstance(value, dict): | 78 elif isinstance(value, dict): |
| 81 for key, value in value.iteritems(): | 79 for key, value in iteritems(value): |
| 82 if not has_safe_repr(key): | 80 if not has_safe_repr(key): |
| 83 return False | 81 return False |
| 84 if not has_safe_repr(value): | 82 if not has_safe_repr(value): |
| 85 return False | 83 return False |
| 86 return True | 84 return True |
| 87 return False | 85 return False |
| 88 | 86 |
| 89 | 87 |
| 90 def find_undeclared(nodes, names): | 88 def find_undeclared(nodes, names): |
| 91 """Check if the names passed are accessed undeclared. The return value | 89 """Check if the names passed are accessed undeclared. The return value |
| (...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 361 doesn't make sense to further process the code. Any block that | 359 doesn't make sense to further process the code. Any block that |
| 362 raises such an exception is not further processed. | 360 raises such an exception is not further processed. |
| 363 """ | 361 """ |
| 364 | 362 |
| 365 | 363 |
| 366 class CodeGenerator(NodeVisitor): | 364 class CodeGenerator(NodeVisitor): |
| 367 | 365 |
| 368 def __init__(self, environment, name, filename, stream=None, | 366 def __init__(self, environment, name, filename, stream=None, |
| 369 defer_init=False): | 367 defer_init=False): |
| 370 if stream is None: | 368 if stream is None: |
| 371 stream = StringIO() | 369 stream = NativeStringIO() |
| 372 self.environment = environment | 370 self.environment = environment |
| 373 self.name = name | 371 self.name = name |
| 374 self.filename = filename | 372 self.filename = filename |
| 375 self.stream = stream | 373 self.stream = stream |
| 376 self.created_block_context = False | 374 self.created_block_context = False |
| 377 self.defer_init = defer_init | 375 self.defer_init = defer_init |
| 378 | 376 |
| 379 # aliases for imports | 377 # aliases for imports |
| 380 self.import_aliases = {} | 378 self.import_aliases = {} |
| 381 | 379 |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 535 | 533 |
| 536 for arg in node.args: | 534 for arg in node.args: |
| 537 self.write(', ') | 535 self.write(', ') |
| 538 self.visit(arg, frame) | 536 self.visit(arg, frame) |
| 539 | 537 |
| 540 if not kwarg_workaround: | 538 if not kwarg_workaround: |
| 541 for kwarg in node.kwargs: | 539 for kwarg in node.kwargs: |
| 542 self.write(', ') | 540 self.write(', ') |
| 543 self.visit(kwarg, frame) | 541 self.visit(kwarg, frame) |
| 544 if extra_kwargs is not None: | 542 if extra_kwargs is not None: |
| 545 for key, value in extra_kwargs.iteritems(): | 543 for key, value in iteritems(extra_kwargs): |
| 546 self.write(', %s=%s' % (key, value)) | 544 self.write(', %s=%s' % (key, value)) |
| 547 if node.dyn_args: | 545 if node.dyn_args: |
| 548 self.write(', *') | 546 self.write(', *') |
| 549 self.visit(node.dyn_args, frame) | 547 self.visit(node.dyn_args, frame) |
| 550 | 548 |
| 551 if kwarg_workaround: | 549 if kwarg_workaround: |
| 552 if node.dyn_kwargs is not None: | 550 if node.dyn_kwargs is not None: |
| 553 self.write(', **dict({') | 551 self.write(', **dict({') |
| 554 else: | 552 else: |
| 555 self.write(', **{') | 553 self.write(', **{') |
| 556 for kwarg in node.kwargs: | 554 for kwarg in node.kwargs: |
| 557 self.write('%r: ' % kwarg.key) | 555 self.write('%r: ' % kwarg.key) |
| 558 self.visit(kwarg.value, frame) | 556 self.visit(kwarg.value, frame) |
| 559 self.write(', ') | 557 self.write(', ') |
| 560 if extra_kwargs is not None: | 558 if extra_kwargs is not None: |
| 561 for key, value in extra_kwargs.iteritems(): | 559 for key, value in iteritems(extra_kwargs): |
| 562 self.write('%r: %s, ' % (key, value)) | 560 self.write('%r: %s, ' % (key, value)) |
| 563 if node.dyn_kwargs is not None: | 561 if node.dyn_kwargs is not None: |
| 564 self.write('}, **') | 562 self.write('}, **') |
| 565 self.visit(node.dyn_kwargs, frame) | 563 self.visit(node.dyn_kwargs, frame) |
| 566 self.write(')') | 564 self.write(')') |
| 567 else: | 565 else: |
| 568 self.write('}') | 566 self.write('}') |
| 569 | 567 |
| 570 elif node.dyn_kwargs is not None: | 568 elif node.dyn_kwargs is not None: |
| 571 self.write(', **') | 569 self.write(', **') |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 618 to_declare = set() | 616 to_declare = set() |
| 619 for name in frame.identifiers.declared_locally: | 617 for name in frame.identifiers.declared_locally: |
| 620 if name not in aliases: | 618 if name not in aliases: |
| 621 to_declare.add('l_' + name) | 619 to_declare.add('l_' + name) |
| 622 if to_declare: | 620 if to_declare: |
| 623 self.writeline(' = '.join(to_declare) + ' = missing') | 621 self.writeline(' = '.join(to_declare) + ' = missing') |
| 624 return aliases | 622 return aliases |
| 625 | 623 |
| 626 def pop_scope(self, aliases, frame): | 624 def pop_scope(self, aliases, frame): |
| 627 """Restore all aliases and delete unused variables.""" | 625 """Restore all aliases and delete unused variables.""" |
| 628 for name, alias in aliases.iteritems(): | 626 for name, alias in iteritems(aliases): |
| 629 self.writeline('l_%s = %s' % (name, alias)) | 627 self.writeline('l_%s = %s' % (name, alias)) |
| 630 to_delete = set() | 628 to_delete = set() |
| 631 for name in frame.identifiers.declared_locally: | 629 for name in frame.identifiers.declared_locally: |
| 632 if name not in aliases: | 630 if name not in aliases: |
| 633 to_delete.add('l_' + name) | 631 to_delete.add('l_' + name) |
| 634 if to_delete: | 632 if to_delete: |
| 635 # we cannot use the del statement here because enclosed | 633 # we cannot use the del statement here because enclosed |
| 636 # scopes can trigger a SyntaxError: | 634 # scopes can trigger a SyntaxError: |
| 637 # a = 42; b = lambda: a; del a | 635 # a = 42; b = lambda: a; del a |
| 638 self.writeline(' = '.join(to_delete) + ' = missing') | 636 self.writeline(' = '.join(to_delete) + ' = missing') |
| (...skipping 17 matching lines...) Expand all Loading... |
| 656 children = list(children) | 654 children = list(children) |
| 657 func_frame = frame.inner() | 655 func_frame = frame.inner() |
| 658 func_frame.inspect(children) | 656 func_frame.inspect(children) |
| 659 | 657 |
| 660 # variables that are undeclared (accessed before declaration) and | 658 # variables that are undeclared (accessed before declaration) and |
| 661 # declared locally *and* part of an outside scope raise a template | 659 # declared locally *and* part of an outside scope raise a template |
| 662 # assertion error. Reason: we can't generate reasonable code from | 660 # assertion error. Reason: we can't generate reasonable code from |
| 663 # it without aliasing all the variables. | 661 # it without aliasing all the variables. |
| 664 # this could be fixed in Python 3 where we have the nonlocal | 662 # this could be fixed in Python 3 where we have the nonlocal |
| 665 # keyword or if we switch to bytecode generation | 663 # keyword or if we switch to bytecode generation |
| 666 overriden_closure_vars = ( | 664 overridden_closure_vars = ( |
| 667 func_frame.identifiers.undeclared & | 665 func_frame.identifiers.undeclared & |
| 668 func_frame.identifiers.declared & | 666 func_frame.identifiers.declared & |
| 669 (func_frame.identifiers.declared_locally | | 667 (func_frame.identifiers.declared_locally | |
| 670 func_frame.identifiers.declared_parameter) | 668 func_frame.identifiers.declared_parameter) |
| 671 ) | 669 ) |
| 672 if overriden_closure_vars: | 670 if overridden_closure_vars: |
| 673 self.fail('It\'s not possible to set and access variables ' | 671 self.fail('It\'s not possible to set and access variables ' |
| 674 'derived from an outer scope! (affects: %s)' % | 672 'derived from an outer scope! (affects: %s)' % |
| 675 ', '.join(sorted(overriden_closure_vars)), node.lineno) | 673 ', '.join(sorted(overridden_closure_vars)), node.lineno) |
| 676 | 674 |
| 677 # remove variables from a closure from the frame's undeclared | 675 # remove variables from a closure from the frame's undeclared |
| 678 # identifiers. | 676 # identifiers. |
| 679 func_frame.identifiers.undeclared -= ( | 677 func_frame.identifiers.undeclared -= ( |
| 680 func_frame.identifiers.undeclared & | 678 func_frame.identifiers.undeclared & |
| 681 func_frame.identifiers.declared | 679 func_frame.identifiers.declared |
| 682 ) | 680 ) |
| 683 | 681 |
| 684 # no special variables for this scope, abort early | 682 # no special variables for this scope, abort early |
| 685 if not find_special: | 683 if not find_special: |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 820 self.indent() | 818 self.indent() |
| 821 self.writeline('if parent_template is not None:') | 819 self.writeline('if parent_template is not None:') |
| 822 self.indent() | 820 self.indent() |
| 823 self.writeline('for event in parent_template.' | 821 self.writeline('for event in parent_template.' |
| 824 'root_render_func(context):') | 822 'root_render_func(context):') |
| 825 self.indent() | 823 self.indent() |
| 826 self.writeline('yield event') | 824 self.writeline('yield event') |
| 827 self.outdent(2 + (not self.has_known_extends)) | 825 self.outdent(2 + (not self.has_known_extends)) |
| 828 | 826 |
| 829 # at this point we now have the blocks collected and can visit them too. | 827 # at this point we now have the blocks collected and can visit them too. |
| 830 for name, block in self.blocks.iteritems(): | 828 for name, block in iteritems(self.blocks): |
| 831 block_frame = Frame(eval_ctx) | 829 block_frame = Frame(eval_ctx) |
| 832 block_frame.inspect(block.body) | 830 block_frame.inspect(block.body) |
| 833 block_frame.block = name | 831 block_frame.block = name |
| 834 self.writeline('def block_%s(context%s):' % (name, envenv), | 832 self.writeline('def block_%s(context%s):' % (name, envenv), |
| 835 block, 1) | 833 block, 1) |
| 836 self.indent() | 834 self.indent() |
| 837 undeclared = find_undeclared(block.body, ('self', 'super')) | 835 undeclared = find_undeclared(block.body, ('self', 'super')) |
| 838 if 'self' in undeclared: | 836 if 'self' in undeclared: |
| 839 block_frame.identifiers.add_special('self') | 837 block_frame.identifiers.add_special('self') |
| 840 self.writeline('l_self = TemplateReference(context)') | 838 self.writeline('l_self = TemplateReference(context)') |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 887 | 885 |
| 888 # if we have a known extends we just add a template runtime | 886 # if we have a known extends we just add a template runtime |
| 889 # error into the generated code. We could catch that at compile | 887 # error into the generated code. We could catch that at compile |
| 890 # time too, but i welcome it not to confuse users by throwing the | 888 # time too, but i welcome it not to confuse users by throwing the |
| 891 # same error at different times just "because we can". | 889 # same error at different times just "because we can". |
| 892 if not self.has_known_extends: | 890 if not self.has_known_extends: |
| 893 self.writeline('if parent_template is not None:') | 891 self.writeline('if parent_template is not None:') |
| 894 self.indent() | 892 self.indent() |
| 895 self.writeline('raise TemplateRuntimeError(%r)' % | 893 self.writeline('raise TemplateRuntimeError(%r)' % |
| 896 'extended multiple times') | 894 'extended multiple times') |
| 897 self.outdent() | |
| 898 | 895 |
| 899 # if we have a known extends already we don't need that code here | 896 # if we have a known extends already we don't need that code here |
| 900 # as we know that the template execution will end here. | 897 # as we know that the template execution will end here. |
| 901 if self.has_known_extends: | 898 if self.has_known_extends: |
| 902 raise CompilerExit() | 899 raise CompilerExit() |
| 900 else: |
| 901 self.outdent() |
| 903 | 902 |
| 904 self.writeline('parent_template = environment.get_template(', node) | 903 self.writeline('parent_template = environment.get_template(', node) |
| 905 self.visit(node.template, frame) | 904 self.visit(node.template, frame) |
| 906 self.write(', %r)' % self.name) | 905 self.write(', %r)' % self.name) |
| 907 self.writeline('for name, parent_block in parent_template.' | 906 self.writeline('for name, parent_block in parent_template.' |
| 908 'blocks.%s():' % dict_item_iter) | 907 'blocks.%s():' % dict_item_iter) |
| 909 self.indent() | 908 self.indent() |
| 910 self.writeline('context.blocks.setdefault(name, []).' | 909 self.writeline('context.blocks.setdefault(name, []).' |
| 911 'append(parent_block)') | 910 'append(parent_block)') |
| 912 self.outdent() | 911 self.outdent() |
| (...skipping 10 matching lines...) Expand all Loading... |
| 923 def visit_Include(self, node, frame): | 922 def visit_Include(self, node, frame): |
| 924 """Handles includes.""" | 923 """Handles includes.""" |
| 925 if node.with_context: | 924 if node.with_context: |
| 926 self.unoptimize_scope(frame) | 925 self.unoptimize_scope(frame) |
| 927 if node.ignore_missing: | 926 if node.ignore_missing: |
| 928 self.writeline('try:') | 927 self.writeline('try:') |
| 929 self.indent() | 928 self.indent() |
| 930 | 929 |
| 931 func_name = 'get_or_select_template' | 930 func_name = 'get_or_select_template' |
| 932 if isinstance(node.template, nodes.Const): | 931 if isinstance(node.template, nodes.Const): |
| 933 if isinstance(node.template.value, basestring): | 932 if isinstance(node.template.value, string_types): |
| 934 func_name = 'get_template' | 933 func_name = 'get_template' |
| 935 elif isinstance(node.template.value, (tuple, list)): | 934 elif isinstance(node.template.value, (tuple, list)): |
| 936 func_name = 'select_template' | 935 func_name = 'select_template' |
| 937 elif isinstance(node.template, (nodes.Tuple, nodes.List)): | 936 elif isinstance(node.template, (nodes.Tuple, nodes.List)): |
| 938 func_name = 'select_template' | 937 func_name = 'select_template' |
| 939 | 938 |
| 940 self.writeline('template = environment.%s(' % func_name, node) | 939 self.writeline('template = environment.%s(' % func_name, node) |
| 941 self.visit(node.template, frame) | 940 self.visit(node.template, frame) |
| 942 self.write(', %r)' % self.name) | 941 self.write(', %r)' % self.name) |
| 943 if node.ignore_missing: | 942 if node.ignore_missing: |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1025 else: | 1024 else: |
| 1026 self.writeline('context.vars.update({%s})' % ', '.join( | 1025 self.writeline('context.vars.update({%s})' % ', '.join( |
| 1027 '%r: l_%s' % (name, name) for name in var_names | 1026 '%r: l_%s' % (name, name) for name in var_names |
| 1028 )) | 1027 )) |
| 1029 if discarded_names: | 1028 if discarded_names: |
| 1030 if len(discarded_names) == 1: | 1029 if len(discarded_names) == 1: |
| 1031 self.writeline('context.exported_vars.discard(%r)' % | 1030 self.writeline('context.exported_vars.discard(%r)' % |
| 1032 discarded_names[0]) | 1031 discarded_names[0]) |
| 1033 else: | 1032 else: |
| 1034 self.writeline('context.exported_vars.difference_' | 1033 self.writeline('context.exported_vars.difference_' |
| 1035 'update((%s))' % ', '.join(map(repr, discarded_na
mes))) | 1034 'update((%s))' % ', '.join(imap(repr, discarded_n
ames))) |
| 1036 | 1035 |
| 1037 def visit_For(self, node, frame): | 1036 def visit_For(self, node, frame): |
| 1038 # when calculating the nodes for the inner frame we have to exclude | 1037 # when calculating the nodes for the inner frame we have to exclude |
| 1039 # the iterator contents from it | 1038 # the iterator contents from it |
| 1040 children = node.iter_child_nodes(exclude=('iter',)) | 1039 children = node.iter_child_nodes(exclude=('iter',)) |
| 1041 if node.recursive: | 1040 if node.recursive: |
| 1042 loop_frame = self.function_scoping(node, frame, children, | 1041 loop_frame = self.function_scoping(node, frame, children, |
| 1043 find_special=False) | 1042 find_special=False) |
| 1044 else: | 1043 else: |
| 1045 loop_frame = frame.inner() | 1044 loop_frame = frame.inner() |
| 1046 loop_frame.inspect(children) | 1045 loop_frame.inspect(children) |
| 1047 | 1046 |
| 1048 # try to figure out if we have an extended loop. An extended loop | 1047 # try to figure out if we have an extended loop. An extended loop |
| 1049 # is necessary if the loop is in recursive mode if the special loop | 1048 # is necessary if the loop is in recursive mode if the special loop |
| 1050 # variable is accessed in the body. | 1049 # variable is accessed in the body. |
| 1051 extended_loop = node.recursive or 'loop' in \ | 1050 extended_loop = node.recursive or 'loop' in \ |
| 1052 find_undeclared(node.iter_child_nodes( | 1051 find_undeclared(node.iter_child_nodes( |
| 1053 only=('body',)), ('loop',)) | 1052 only=('body',)), ('loop',)) |
| 1054 | 1053 |
| 1055 # if we don't have an recursive loop we have to find the shadowed | 1054 # if we don't have an recursive loop we have to find the shadowed |
| 1056 # variables at that point. Because loops can be nested but the loop | 1055 # variables at that point. Because loops can be nested but the loop |
| 1057 # variable is a special one we have to enforce aliasing for it. | 1056 # variable is a special one we have to enforce aliasing for it. |
| 1058 if not node.recursive: | 1057 if not node.recursive: |
| 1059 aliases = self.push_scope(loop_frame, ('loop',)) | 1058 aliases = self.push_scope(loop_frame, ('loop',)) |
| 1060 | 1059 |
| 1061 # otherwise we set up a buffer and add a function def | 1060 # otherwise we set up a buffer and add a function def |
| 1062 else: | 1061 else: |
| 1063 self.writeline('def loop(reciter, loop_render_func):', node) | 1062 self.writeline('def loop(reciter, loop_render_func, depth=0):', node
) |
| 1064 self.indent() | 1063 self.indent() |
| 1065 self.buffer(loop_frame) | 1064 self.buffer(loop_frame) |
| 1066 aliases = {} | 1065 aliases = {} |
| 1067 | 1066 |
| 1068 # make sure the loop variable is a special one and raise a template | 1067 # make sure the loop variable is a special one and raise a template |
| 1069 # assertion error if a loop tries to write to loop | 1068 # assertion error if a loop tries to write to loop |
| 1070 if extended_loop: | 1069 if extended_loop: |
| 1070 self.writeline('l_loop = missing') |
| 1071 loop_frame.identifiers.add_special('loop') | 1071 loop_frame.identifiers.add_special('loop') |
| 1072 for name in node.find_all(nodes.Name): | 1072 for name in node.find_all(nodes.Name): |
| 1073 if name.ctx == 'store' and name.name == 'loop': | 1073 if name.ctx == 'store' and name.name == 'loop': |
| 1074 self.fail('Can\'t assign to special loop variable ' | 1074 self.fail('Can\'t assign to special loop variable ' |
| 1075 'in for-loop target', name.lineno) | 1075 'in for-loop target', name.lineno) |
| 1076 | 1076 |
| 1077 self.pull_locals(loop_frame) | 1077 self.pull_locals(loop_frame) |
| 1078 if node.else_: | 1078 if node.else_: |
| 1079 iteration_indicator = self.temporary_identifier() | 1079 iteration_indicator = self.temporary_identifier() |
| 1080 self.writeline('%s = 1' % iteration_indicator) | 1080 self.writeline('%s = 1' % iteration_indicator) |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1111 test_frame = loop_frame.copy() | 1111 test_frame = loop_frame.copy() |
| 1112 self.visit(node.test, test_frame) | 1112 self.visit(node.test, test_frame) |
| 1113 self.write('))') | 1113 self.write('))') |
| 1114 | 1114 |
| 1115 elif node.recursive: | 1115 elif node.recursive: |
| 1116 self.write('reciter') | 1116 self.write('reciter') |
| 1117 else: | 1117 else: |
| 1118 self.visit(node.iter, loop_frame) | 1118 self.visit(node.iter, loop_frame) |
| 1119 | 1119 |
| 1120 if node.recursive: | 1120 if node.recursive: |
| 1121 self.write(', recurse=loop_render_func):') | 1121 self.write(', loop_render_func, depth):') |
| 1122 else: | 1122 else: |
| 1123 self.write(extended_loop and '):' or ':') | 1123 self.write(extended_loop and '):' or ':') |
| 1124 | 1124 |
| 1125 # tests in not extended loops become a continue | 1125 # tests in not extended loops become a continue |
| 1126 if not extended_loop and node.test is not None: | 1126 if not extended_loop and node.test is not None: |
| 1127 self.indent() | 1127 self.indent() |
| 1128 self.writeline('if not ') | 1128 self.writeline('if not ') |
| 1129 self.visit(node.test, loop_frame) | 1129 self.visit(node.test, loop_frame) |
| 1130 self.write(':') | 1130 self.write(':') |
| 1131 self.indent() | 1131 self.indent() |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1209 self.newline(node) | 1209 self.newline(node) |
| 1210 self.visit(node.node, frame) | 1210 self.visit(node.node, frame) |
| 1211 | 1211 |
| 1212 def visit_Output(self, node, frame): | 1212 def visit_Output(self, node, frame): |
| 1213 # if we have a known extends statement, we don't output anything | 1213 # if we have a known extends statement, we don't output anything |
| 1214 # if we are in a require_output_check section | 1214 # if we are in a require_output_check section |
| 1215 if self.has_known_extends and frame.require_output_check: | 1215 if self.has_known_extends and frame.require_output_check: |
| 1216 return | 1216 return |
| 1217 | 1217 |
| 1218 if self.environment.finalize: | 1218 if self.environment.finalize: |
| 1219 finalize = lambda x: unicode(self.environment.finalize(x)) | 1219 finalize = lambda x: text_type(self.environment.finalize(x)) |
| 1220 else: | 1220 else: |
| 1221 finalize = unicode | 1221 finalize = text_type |
| 1222 | 1222 |
| 1223 # if we are inside a frame that requires output checking, we do so | 1223 # if we are inside a frame that requires output checking, we do so |
| 1224 outdent_later = False | 1224 outdent_later = False |
| 1225 if frame.require_output_check: | 1225 if frame.require_output_check: |
| 1226 self.writeline('if parent_template is None:') | 1226 self.writeline('if parent_template is None:') |
| 1227 self.indent() | 1227 self.indent() |
| 1228 outdent_later = True | 1228 outdent_later = True |
| 1229 | 1229 |
| 1230 # try to evaluate as many chunks as possible into a static | 1230 # try to evaluate as many chunks as possible into a static |
| 1231 # string at compile time. | 1231 # string at compile time. |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1360 if idx: | 1360 if idx: |
| 1361 self.write(', ') | 1361 self.write(', ') |
| 1362 self.write('%r: l_%s' % (name, name)) | 1362 self.write('%r: l_%s' % (name, name)) |
| 1363 self.write('})') | 1363 self.write('})') |
| 1364 if public_names: | 1364 if public_names: |
| 1365 if len(public_names) == 1: | 1365 if len(public_names) == 1: |
| 1366 self.writeline('context.exported_vars.add(%r)' % | 1366 self.writeline('context.exported_vars.add(%r)' % |
| 1367 public_names[0]) | 1367 public_names[0]) |
| 1368 else: | 1368 else: |
| 1369 self.writeline('context.exported_vars.update((%s))' % | 1369 self.writeline('context.exported_vars.update((%s))' % |
| 1370 ', '.join(map(repr, public_names))) | 1370 ', '.join(imap(repr, public_names))) |
| 1371 | 1371 |
| 1372 # -- Expression Visitors | 1372 # -- Expression Visitors |
| 1373 | 1373 |
| 1374 def visit_Name(self, node, frame): | 1374 def visit_Name(self, node, frame): |
| 1375 if node.ctx == 'store' and frame.toplevel: | 1375 if node.ctx == 'store' and frame.toplevel: |
| 1376 frame.toplevel_assignments.add(node.name) | 1376 frame.toplevel_assignments.add(node.name) |
| 1377 self.write('l_' + node.name) | 1377 self.write('l_' + node.name) |
| 1378 frame.assigned_names.add(node.name) | 1378 frame.assigned_names.add(node.name) |
| 1379 | 1379 |
| 1380 def visit_Const(self, node, frame): | 1380 def visit_Const(self, node, frame): |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1548 self.write(')') | 1548 self.write(')') |
| 1549 | 1549 |
| 1550 def visit_CondExpr(self, node, frame): | 1550 def visit_CondExpr(self, node, frame): |
| 1551 def write_expr2(): | 1551 def write_expr2(): |
| 1552 if node.expr2 is not None: | 1552 if node.expr2 is not None: |
| 1553 return self.visit(node.expr2, frame) | 1553 return self.visit(node.expr2, frame) |
| 1554 self.write('environment.undefined(%r)' % ('the inline if-' | 1554 self.write('environment.undefined(%r)' % ('the inline if-' |
| 1555 'expression on %s evaluated to false and ' | 1555 'expression on %s evaluated to false and ' |
| 1556 'no else section was defined.' % self.position(node))) | 1556 'no else section was defined.' % self.position(node))) |
| 1557 | 1557 |
| 1558 if not have_condexpr: | 1558 self.write('(') |
| 1559 self.write('((') | 1559 self.visit(node.expr1, frame) |
| 1560 self.visit(node.test, frame) | 1560 self.write(' if ') |
| 1561 self.write(') and (') | 1561 self.visit(node.test, frame) |
| 1562 self.visit(node.expr1, frame) | 1562 self.write(' else ') |
| 1563 self.write(',) or (') | 1563 write_expr2() |
| 1564 write_expr2() | 1564 self.write(')') |
| 1565 self.write(',))[0]') | |
| 1566 else: | |
| 1567 self.write('(') | |
| 1568 self.visit(node.expr1, frame) | |
| 1569 self.write(' if ') | |
| 1570 self.visit(node.test, frame) | |
| 1571 self.write(' else ') | |
| 1572 write_expr2() | |
| 1573 self.write(')') | |
| 1574 | 1565 |
| 1575 def visit_Call(self, node, frame, forward_caller=False): | 1566 def visit_Call(self, node, frame, forward_caller=False): |
| 1576 if self.environment.sandboxed: | 1567 if self.environment.sandboxed: |
| 1577 self.write('environment.call(context, ') | 1568 self.write('environment.call(context, ') |
| 1578 else: | 1569 else: |
| 1579 self.write('context.call(') | 1570 self.write('context.call(') |
| 1580 self.visit(node.node, frame) | 1571 self.visit(node.node, frame) |
| 1581 extra_kwargs = forward_caller and {'caller': 'caller'} or None | 1572 extra_kwargs = forward_caller and {'caller': 'caller'} or None |
| 1582 self.signature(node, frame, extra_kwargs) | 1573 self.signature(node, frame, extra_kwargs) |
| 1583 self.write(')') | 1574 self.write(')') |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1640 | 1631 |
| 1641 def visit_ScopedEvalContextModifier(self, node, frame): | 1632 def visit_ScopedEvalContextModifier(self, node, frame): |
| 1642 old_ctx_name = self.temporary_identifier() | 1633 old_ctx_name = self.temporary_identifier() |
| 1643 safed_ctx = frame.eval_ctx.save() | 1634 safed_ctx = frame.eval_ctx.save() |
| 1644 self.writeline('%s = context.eval_ctx.save()' % old_ctx_name) | 1635 self.writeline('%s = context.eval_ctx.save()' % old_ctx_name) |
| 1645 self.visit_EvalContextModifier(node, frame) | 1636 self.visit_EvalContextModifier(node, frame) |
| 1646 for child in node.body: | 1637 for child in node.body: |
| 1647 self.visit(child, frame) | 1638 self.visit(child, frame) |
| 1648 frame.eval_ctx.revert(safed_ctx) | 1639 frame.eval_ctx.revert(safed_ctx) |
| 1649 self.writeline('context.eval_ctx.revert(%s)' % old_ctx_name) | 1640 self.writeline('context.eval_ctx.revert(%s)' % old_ctx_name) |
| OLD | NEW |