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 |