11cb0ef41Sopenharmony_ci# -*- coding: utf-8 -*- 21cb0ef41Sopenharmony_ci""" 31cb0ef41Sopenharmony_ci jinja2.compiler 41cb0ef41Sopenharmony_ci ~~~~~~~~~~~~~~~ 51cb0ef41Sopenharmony_ci 61cb0ef41Sopenharmony_ci Compiles nodes into python code. 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ci :copyright: (c) 2017 by the Jinja Team. 91cb0ef41Sopenharmony_ci :license: BSD, see LICENSE for more details. 101cb0ef41Sopenharmony_ci""" 111cb0ef41Sopenharmony_cifrom itertools import chain 121cb0ef41Sopenharmony_cifrom copy import deepcopy 131cb0ef41Sopenharmony_cifrom keyword import iskeyword as is_python_keyword 141cb0ef41Sopenharmony_cifrom functools import update_wrapper 151cb0ef41Sopenharmony_cifrom jinja2 import nodes 161cb0ef41Sopenharmony_cifrom jinja2.nodes import EvalContext 171cb0ef41Sopenharmony_cifrom jinja2.visitor import NodeVisitor 181cb0ef41Sopenharmony_cifrom jinja2.optimizer import Optimizer 191cb0ef41Sopenharmony_cifrom jinja2.exceptions import TemplateAssertionError 201cb0ef41Sopenharmony_cifrom jinja2.utils import Markup, concat, escape 211cb0ef41Sopenharmony_cifrom jinja2._compat import range_type, text_type, string_types, \ 221cb0ef41Sopenharmony_ci iteritems, NativeStringIO, imap, izip 231cb0ef41Sopenharmony_cifrom jinja2.idtracking import Symbols, VAR_LOAD_PARAMETER, \ 241cb0ef41Sopenharmony_ci VAR_LOAD_RESOLVE, VAR_LOAD_ALIAS, VAR_LOAD_UNDEFINED 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ci 271cb0ef41Sopenharmony_cioperators = { 281cb0ef41Sopenharmony_ci 'eq': '==', 291cb0ef41Sopenharmony_ci 'ne': '!=', 301cb0ef41Sopenharmony_ci 'gt': '>', 311cb0ef41Sopenharmony_ci 'gteq': '>=', 321cb0ef41Sopenharmony_ci 'lt': '<', 331cb0ef41Sopenharmony_ci 'lteq': '<=', 341cb0ef41Sopenharmony_ci 'in': 'in', 351cb0ef41Sopenharmony_ci 'notin': 'not in' 361cb0ef41Sopenharmony_ci} 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_ci# what method to iterate over items do we want to use for dict iteration 391cb0ef41Sopenharmony_ci# in generated code? on 2.x let's go with iteritems, on 3.x with items 401cb0ef41Sopenharmony_ciif hasattr(dict, 'iteritems'): 411cb0ef41Sopenharmony_ci dict_item_iter = 'iteritems' 421cb0ef41Sopenharmony_cielse: 431cb0ef41Sopenharmony_ci dict_item_iter = 'items' 441cb0ef41Sopenharmony_ci 451cb0ef41Sopenharmony_cicode_features = ['division'] 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ci# does this python version support generator stops? (PEP 0479) 481cb0ef41Sopenharmony_citry: 491cb0ef41Sopenharmony_ci exec('from __future__ import generator_stop') 501cb0ef41Sopenharmony_ci code_features.append('generator_stop') 511cb0ef41Sopenharmony_ciexcept SyntaxError: 521cb0ef41Sopenharmony_ci pass 531cb0ef41Sopenharmony_ci 541cb0ef41Sopenharmony_ci# does this python version support yield from? 551cb0ef41Sopenharmony_citry: 561cb0ef41Sopenharmony_ci exec('def f(): yield from x()') 571cb0ef41Sopenharmony_ciexcept SyntaxError: 581cb0ef41Sopenharmony_ci supports_yield_from = False 591cb0ef41Sopenharmony_cielse: 601cb0ef41Sopenharmony_ci supports_yield_from = True 611cb0ef41Sopenharmony_ci 621cb0ef41Sopenharmony_ci 631cb0ef41Sopenharmony_cidef optimizeconst(f): 641cb0ef41Sopenharmony_ci def new_func(self, node, frame, **kwargs): 651cb0ef41Sopenharmony_ci # Only optimize if the frame is not volatile 661cb0ef41Sopenharmony_ci if self.optimized and not frame.eval_ctx.volatile: 671cb0ef41Sopenharmony_ci new_node = self.optimizer.visit(node, frame.eval_ctx) 681cb0ef41Sopenharmony_ci if new_node != node: 691cb0ef41Sopenharmony_ci return self.visit(new_node, frame) 701cb0ef41Sopenharmony_ci return f(self, node, frame, **kwargs) 711cb0ef41Sopenharmony_ci return update_wrapper(new_func, f) 721cb0ef41Sopenharmony_ci 731cb0ef41Sopenharmony_ci 741cb0ef41Sopenharmony_cidef generate(node, environment, name, filename, stream=None, 751cb0ef41Sopenharmony_ci defer_init=False, optimized=True): 761cb0ef41Sopenharmony_ci """Generate the python source for a node tree.""" 771cb0ef41Sopenharmony_ci if not isinstance(node, nodes.Template): 781cb0ef41Sopenharmony_ci raise TypeError('Can\'t compile non template nodes') 791cb0ef41Sopenharmony_ci generator = environment.code_generator_class(environment, name, filename, 801cb0ef41Sopenharmony_ci stream, defer_init, 811cb0ef41Sopenharmony_ci optimized) 821cb0ef41Sopenharmony_ci generator.visit(node) 831cb0ef41Sopenharmony_ci if stream is None: 841cb0ef41Sopenharmony_ci return generator.stream.getvalue() 851cb0ef41Sopenharmony_ci 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_cidef has_safe_repr(value): 881cb0ef41Sopenharmony_ci """Does the node have a safe representation?""" 891cb0ef41Sopenharmony_ci if value is None or value is NotImplemented or value is Ellipsis: 901cb0ef41Sopenharmony_ci return True 911cb0ef41Sopenharmony_ci if type(value) in (bool, int, float, complex, range_type, Markup) + string_types: 921cb0ef41Sopenharmony_ci return True 931cb0ef41Sopenharmony_ci if type(value) in (tuple, list, set, frozenset): 941cb0ef41Sopenharmony_ci for item in value: 951cb0ef41Sopenharmony_ci if not has_safe_repr(item): 961cb0ef41Sopenharmony_ci return False 971cb0ef41Sopenharmony_ci return True 981cb0ef41Sopenharmony_ci elif type(value) is dict: 991cb0ef41Sopenharmony_ci for key, value in iteritems(value): 1001cb0ef41Sopenharmony_ci if not has_safe_repr(key): 1011cb0ef41Sopenharmony_ci return False 1021cb0ef41Sopenharmony_ci if not has_safe_repr(value): 1031cb0ef41Sopenharmony_ci return False 1041cb0ef41Sopenharmony_ci return True 1051cb0ef41Sopenharmony_ci return False 1061cb0ef41Sopenharmony_ci 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_cidef find_undeclared(nodes, names): 1091cb0ef41Sopenharmony_ci """Check if the names passed are accessed undeclared. The return value 1101cb0ef41Sopenharmony_ci is a set of all the undeclared names from the sequence of names found. 1111cb0ef41Sopenharmony_ci """ 1121cb0ef41Sopenharmony_ci visitor = UndeclaredNameVisitor(names) 1131cb0ef41Sopenharmony_ci try: 1141cb0ef41Sopenharmony_ci for node in nodes: 1151cb0ef41Sopenharmony_ci visitor.visit(node) 1161cb0ef41Sopenharmony_ci except VisitorExit: 1171cb0ef41Sopenharmony_ci pass 1181cb0ef41Sopenharmony_ci return visitor.undeclared 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_ci 1211cb0ef41Sopenharmony_ciclass MacroRef(object): 1221cb0ef41Sopenharmony_ci 1231cb0ef41Sopenharmony_ci def __init__(self, node): 1241cb0ef41Sopenharmony_ci self.node = node 1251cb0ef41Sopenharmony_ci self.accesses_caller = False 1261cb0ef41Sopenharmony_ci self.accesses_kwargs = False 1271cb0ef41Sopenharmony_ci self.accesses_varargs = False 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_ciclass Frame(object): 1311cb0ef41Sopenharmony_ci """Holds compile time information for us.""" 1321cb0ef41Sopenharmony_ci 1331cb0ef41Sopenharmony_ci def __init__(self, eval_ctx, parent=None, level=None): 1341cb0ef41Sopenharmony_ci self.eval_ctx = eval_ctx 1351cb0ef41Sopenharmony_ci self.symbols = Symbols(parent and parent.symbols or None, 1361cb0ef41Sopenharmony_ci level=level) 1371cb0ef41Sopenharmony_ci 1381cb0ef41Sopenharmony_ci # a toplevel frame is the root + soft frames such as if conditions. 1391cb0ef41Sopenharmony_ci self.toplevel = False 1401cb0ef41Sopenharmony_ci 1411cb0ef41Sopenharmony_ci # the root frame is basically just the outermost frame, so no if 1421cb0ef41Sopenharmony_ci # conditions. This information is used to optimize inheritance 1431cb0ef41Sopenharmony_ci # situations. 1441cb0ef41Sopenharmony_ci self.rootlevel = False 1451cb0ef41Sopenharmony_ci 1461cb0ef41Sopenharmony_ci # in some dynamic inheritance situations the compiler needs to add 1471cb0ef41Sopenharmony_ci # write tests around output statements. 1481cb0ef41Sopenharmony_ci self.require_output_check = parent and parent.require_output_check 1491cb0ef41Sopenharmony_ci 1501cb0ef41Sopenharmony_ci # inside some tags we are using a buffer rather than yield statements. 1511cb0ef41Sopenharmony_ci # this for example affects {% filter %} or {% macro %}. If a frame 1521cb0ef41Sopenharmony_ci # is buffered this variable points to the name of the list used as 1531cb0ef41Sopenharmony_ci # buffer. 1541cb0ef41Sopenharmony_ci self.buffer = None 1551cb0ef41Sopenharmony_ci 1561cb0ef41Sopenharmony_ci # the name of the block we're in, otherwise None. 1571cb0ef41Sopenharmony_ci self.block = parent and parent.block or None 1581cb0ef41Sopenharmony_ci 1591cb0ef41Sopenharmony_ci # the parent of this frame 1601cb0ef41Sopenharmony_ci self.parent = parent 1611cb0ef41Sopenharmony_ci 1621cb0ef41Sopenharmony_ci if parent is not None: 1631cb0ef41Sopenharmony_ci self.buffer = parent.buffer 1641cb0ef41Sopenharmony_ci 1651cb0ef41Sopenharmony_ci def copy(self): 1661cb0ef41Sopenharmony_ci """Create a copy of the current one.""" 1671cb0ef41Sopenharmony_ci rv = object.__new__(self.__class__) 1681cb0ef41Sopenharmony_ci rv.__dict__.update(self.__dict__) 1691cb0ef41Sopenharmony_ci rv.symbols = self.symbols.copy() 1701cb0ef41Sopenharmony_ci return rv 1711cb0ef41Sopenharmony_ci 1721cb0ef41Sopenharmony_ci def inner(self, isolated=False): 1731cb0ef41Sopenharmony_ci """Return an inner frame.""" 1741cb0ef41Sopenharmony_ci if isolated: 1751cb0ef41Sopenharmony_ci return Frame(self.eval_ctx, level=self.symbols.level + 1) 1761cb0ef41Sopenharmony_ci return Frame(self.eval_ctx, self) 1771cb0ef41Sopenharmony_ci 1781cb0ef41Sopenharmony_ci def soft(self): 1791cb0ef41Sopenharmony_ci """Return a soft frame. A soft frame may not be modified as 1801cb0ef41Sopenharmony_ci standalone thing as it shares the resources with the frame it 1811cb0ef41Sopenharmony_ci was created of, but it's not a rootlevel frame any longer. 1821cb0ef41Sopenharmony_ci 1831cb0ef41Sopenharmony_ci This is only used to implement if-statements. 1841cb0ef41Sopenharmony_ci """ 1851cb0ef41Sopenharmony_ci rv = self.copy() 1861cb0ef41Sopenharmony_ci rv.rootlevel = False 1871cb0ef41Sopenharmony_ci return rv 1881cb0ef41Sopenharmony_ci 1891cb0ef41Sopenharmony_ci __copy__ = copy 1901cb0ef41Sopenharmony_ci 1911cb0ef41Sopenharmony_ci 1921cb0ef41Sopenharmony_ciclass VisitorExit(RuntimeError): 1931cb0ef41Sopenharmony_ci """Exception used by the `UndeclaredNameVisitor` to signal a stop.""" 1941cb0ef41Sopenharmony_ci 1951cb0ef41Sopenharmony_ci 1961cb0ef41Sopenharmony_ciclass DependencyFinderVisitor(NodeVisitor): 1971cb0ef41Sopenharmony_ci """A visitor that collects filter and test calls.""" 1981cb0ef41Sopenharmony_ci 1991cb0ef41Sopenharmony_ci def __init__(self): 2001cb0ef41Sopenharmony_ci self.filters = set() 2011cb0ef41Sopenharmony_ci self.tests = set() 2021cb0ef41Sopenharmony_ci 2031cb0ef41Sopenharmony_ci def visit_Filter(self, node): 2041cb0ef41Sopenharmony_ci self.generic_visit(node) 2051cb0ef41Sopenharmony_ci self.filters.add(node.name) 2061cb0ef41Sopenharmony_ci 2071cb0ef41Sopenharmony_ci def visit_Test(self, node): 2081cb0ef41Sopenharmony_ci self.generic_visit(node) 2091cb0ef41Sopenharmony_ci self.tests.add(node.name) 2101cb0ef41Sopenharmony_ci 2111cb0ef41Sopenharmony_ci def visit_Block(self, node): 2121cb0ef41Sopenharmony_ci """Stop visiting at blocks.""" 2131cb0ef41Sopenharmony_ci 2141cb0ef41Sopenharmony_ci 2151cb0ef41Sopenharmony_ciclass UndeclaredNameVisitor(NodeVisitor): 2161cb0ef41Sopenharmony_ci """A visitor that checks if a name is accessed without being 2171cb0ef41Sopenharmony_ci declared. This is different from the frame visitor as it will 2181cb0ef41Sopenharmony_ci not stop at closure frames. 2191cb0ef41Sopenharmony_ci """ 2201cb0ef41Sopenharmony_ci 2211cb0ef41Sopenharmony_ci def __init__(self, names): 2221cb0ef41Sopenharmony_ci self.names = set(names) 2231cb0ef41Sopenharmony_ci self.undeclared = set() 2241cb0ef41Sopenharmony_ci 2251cb0ef41Sopenharmony_ci def visit_Name(self, node): 2261cb0ef41Sopenharmony_ci if node.ctx == 'load' and node.name in self.names: 2271cb0ef41Sopenharmony_ci self.undeclared.add(node.name) 2281cb0ef41Sopenharmony_ci if self.undeclared == self.names: 2291cb0ef41Sopenharmony_ci raise VisitorExit() 2301cb0ef41Sopenharmony_ci else: 2311cb0ef41Sopenharmony_ci self.names.discard(node.name) 2321cb0ef41Sopenharmony_ci 2331cb0ef41Sopenharmony_ci def visit_Block(self, node): 2341cb0ef41Sopenharmony_ci """Stop visiting a blocks.""" 2351cb0ef41Sopenharmony_ci 2361cb0ef41Sopenharmony_ci 2371cb0ef41Sopenharmony_ciclass CompilerExit(Exception): 2381cb0ef41Sopenharmony_ci """Raised if the compiler encountered a situation where it just 2391cb0ef41Sopenharmony_ci doesn't make sense to further process the code. Any block that 2401cb0ef41Sopenharmony_ci raises such an exception is not further processed. 2411cb0ef41Sopenharmony_ci """ 2421cb0ef41Sopenharmony_ci 2431cb0ef41Sopenharmony_ci 2441cb0ef41Sopenharmony_ciclass CodeGenerator(NodeVisitor): 2451cb0ef41Sopenharmony_ci 2461cb0ef41Sopenharmony_ci def __init__(self, environment, name, filename, stream=None, 2471cb0ef41Sopenharmony_ci defer_init=False, optimized=True): 2481cb0ef41Sopenharmony_ci if stream is None: 2491cb0ef41Sopenharmony_ci stream = NativeStringIO() 2501cb0ef41Sopenharmony_ci self.environment = environment 2511cb0ef41Sopenharmony_ci self.name = name 2521cb0ef41Sopenharmony_ci self.filename = filename 2531cb0ef41Sopenharmony_ci self.stream = stream 2541cb0ef41Sopenharmony_ci self.created_block_context = False 2551cb0ef41Sopenharmony_ci self.defer_init = defer_init 2561cb0ef41Sopenharmony_ci self.optimized = optimized 2571cb0ef41Sopenharmony_ci if optimized: 2581cb0ef41Sopenharmony_ci self.optimizer = Optimizer(environment) 2591cb0ef41Sopenharmony_ci 2601cb0ef41Sopenharmony_ci # aliases for imports 2611cb0ef41Sopenharmony_ci self.import_aliases = {} 2621cb0ef41Sopenharmony_ci 2631cb0ef41Sopenharmony_ci # a registry for all blocks. Because blocks are moved out 2641cb0ef41Sopenharmony_ci # into the global python scope they are registered here 2651cb0ef41Sopenharmony_ci self.blocks = {} 2661cb0ef41Sopenharmony_ci 2671cb0ef41Sopenharmony_ci # the number of extends statements so far 2681cb0ef41Sopenharmony_ci self.extends_so_far = 0 2691cb0ef41Sopenharmony_ci 2701cb0ef41Sopenharmony_ci # some templates have a rootlevel extends. In this case we 2711cb0ef41Sopenharmony_ci # can safely assume that we're a child template and do some 2721cb0ef41Sopenharmony_ci # more optimizations. 2731cb0ef41Sopenharmony_ci self.has_known_extends = False 2741cb0ef41Sopenharmony_ci 2751cb0ef41Sopenharmony_ci # the current line number 2761cb0ef41Sopenharmony_ci self.code_lineno = 1 2771cb0ef41Sopenharmony_ci 2781cb0ef41Sopenharmony_ci # registry of all filters and tests (global, not block local) 2791cb0ef41Sopenharmony_ci self.tests = {} 2801cb0ef41Sopenharmony_ci self.filters = {} 2811cb0ef41Sopenharmony_ci 2821cb0ef41Sopenharmony_ci # the debug information 2831cb0ef41Sopenharmony_ci self.debug_info = [] 2841cb0ef41Sopenharmony_ci self._write_debug_info = None 2851cb0ef41Sopenharmony_ci 2861cb0ef41Sopenharmony_ci # the number of new lines before the next write() 2871cb0ef41Sopenharmony_ci self._new_lines = 0 2881cb0ef41Sopenharmony_ci 2891cb0ef41Sopenharmony_ci # the line number of the last written statement 2901cb0ef41Sopenharmony_ci self._last_line = 0 2911cb0ef41Sopenharmony_ci 2921cb0ef41Sopenharmony_ci # true if nothing was written so far. 2931cb0ef41Sopenharmony_ci self._first_write = True 2941cb0ef41Sopenharmony_ci 2951cb0ef41Sopenharmony_ci # used by the `temporary_identifier` method to get new 2961cb0ef41Sopenharmony_ci # unique, temporary identifier 2971cb0ef41Sopenharmony_ci self._last_identifier = 0 2981cb0ef41Sopenharmony_ci 2991cb0ef41Sopenharmony_ci # the current indentation 3001cb0ef41Sopenharmony_ci self._indentation = 0 3011cb0ef41Sopenharmony_ci 3021cb0ef41Sopenharmony_ci # Tracks toplevel assignments 3031cb0ef41Sopenharmony_ci self._assign_stack = [] 3041cb0ef41Sopenharmony_ci 3051cb0ef41Sopenharmony_ci # Tracks parameter definition blocks 3061cb0ef41Sopenharmony_ci self._param_def_block = [] 3071cb0ef41Sopenharmony_ci 3081cb0ef41Sopenharmony_ci # Tracks the current context. 3091cb0ef41Sopenharmony_ci self._context_reference_stack = ['context'] 3101cb0ef41Sopenharmony_ci 3111cb0ef41Sopenharmony_ci # -- Various compilation helpers 3121cb0ef41Sopenharmony_ci 3131cb0ef41Sopenharmony_ci def fail(self, msg, lineno): 3141cb0ef41Sopenharmony_ci """Fail with a :exc:`TemplateAssertionError`.""" 3151cb0ef41Sopenharmony_ci raise TemplateAssertionError(msg, lineno, self.name, self.filename) 3161cb0ef41Sopenharmony_ci 3171cb0ef41Sopenharmony_ci def temporary_identifier(self): 3181cb0ef41Sopenharmony_ci """Get a new unique identifier.""" 3191cb0ef41Sopenharmony_ci self._last_identifier += 1 3201cb0ef41Sopenharmony_ci return 't_%d' % self._last_identifier 3211cb0ef41Sopenharmony_ci 3221cb0ef41Sopenharmony_ci def buffer(self, frame): 3231cb0ef41Sopenharmony_ci """Enable buffering for the frame from that point onwards.""" 3241cb0ef41Sopenharmony_ci frame.buffer = self.temporary_identifier() 3251cb0ef41Sopenharmony_ci self.writeline('%s = []' % frame.buffer) 3261cb0ef41Sopenharmony_ci 3271cb0ef41Sopenharmony_ci def return_buffer_contents(self, frame, force_unescaped=False): 3281cb0ef41Sopenharmony_ci """Return the buffer contents of the frame.""" 3291cb0ef41Sopenharmony_ci if not force_unescaped: 3301cb0ef41Sopenharmony_ci if frame.eval_ctx.volatile: 3311cb0ef41Sopenharmony_ci self.writeline('if context.eval_ctx.autoescape:') 3321cb0ef41Sopenharmony_ci self.indent() 3331cb0ef41Sopenharmony_ci self.writeline('return Markup(concat(%s))' % frame.buffer) 3341cb0ef41Sopenharmony_ci self.outdent() 3351cb0ef41Sopenharmony_ci self.writeline('else:') 3361cb0ef41Sopenharmony_ci self.indent() 3371cb0ef41Sopenharmony_ci self.writeline('return concat(%s)' % frame.buffer) 3381cb0ef41Sopenharmony_ci self.outdent() 3391cb0ef41Sopenharmony_ci return 3401cb0ef41Sopenharmony_ci elif frame.eval_ctx.autoescape: 3411cb0ef41Sopenharmony_ci self.writeline('return Markup(concat(%s))' % frame.buffer) 3421cb0ef41Sopenharmony_ci return 3431cb0ef41Sopenharmony_ci self.writeline('return concat(%s)' % frame.buffer) 3441cb0ef41Sopenharmony_ci 3451cb0ef41Sopenharmony_ci def indent(self): 3461cb0ef41Sopenharmony_ci """Indent by one.""" 3471cb0ef41Sopenharmony_ci self._indentation += 1 3481cb0ef41Sopenharmony_ci 3491cb0ef41Sopenharmony_ci def outdent(self, step=1): 3501cb0ef41Sopenharmony_ci """Outdent by step.""" 3511cb0ef41Sopenharmony_ci self._indentation -= step 3521cb0ef41Sopenharmony_ci 3531cb0ef41Sopenharmony_ci def start_write(self, frame, node=None): 3541cb0ef41Sopenharmony_ci """Yield or write into the frame buffer.""" 3551cb0ef41Sopenharmony_ci if frame.buffer is None: 3561cb0ef41Sopenharmony_ci self.writeline('yield ', node) 3571cb0ef41Sopenharmony_ci else: 3581cb0ef41Sopenharmony_ci self.writeline('%s.append(' % frame.buffer, node) 3591cb0ef41Sopenharmony_ci 3601cb0ef41Sopenharmony_ci def end_write(self, frame): 3611cb0ef41Sopenharmony_ci """End the writing process started by `start_write`.""" 3621cb0ef41Sopenharmony_ci if frame.buffer is not None: 3631cb0ef41Sopenharmony_ci self.write(')') 3641cb0ef41Sopenharmony_ci 3651cb0ef41Sopenharmony_ci def simple_write(self, s, frame, node=None): 3661cb0ef41Sopenharmony_ci """Simple shortcut for start_write + write + end_write.""" 3671cb0ef41Sopenharmony_ci self.start_write(frame, node) 3681cb0ef41Sopenharmony_ci self.write(s) 3691cb0ef41Sopenharmony_ci self.end_write(frame) 3701cb0ef41Sopenharmony_ci 3711cb0ef41Sopenharmony_ci def blockvisit(self, nodes, frame): 3721cb0ef41Sopenharmony_ci """Visit a list of nodes as block in a frame. If the current frame 3731cb0ef41Sopenharmony_ci is no buffer a dummy ``if 0: yield None`` is written automatically. 3741cb0ef41Sopenharmony_ci """ 3751cb0ef41Sopenharmony_ci try: 3761cb0ef41Sopenharmony_ci self.writeline('pass') 3771cb0ef41Sopenharmony_ci for node in nodes: 3781cb0ef41Sopenharmony_ci self.visit(node, frame) 3791cb0ef41Sopenharmony_ci except CompilerExit: 3801cb0ef41Sopenharmony_ci pass 3811cb0ef41Sopenharmony_ci 3821cb0ef41Sopenharmony_ci def write(self, x): 3831cb0ef41Sopenharmony_ci """Write a string into the output stream.""" 3841cb0ef41Sopenharmony_ci if self._new_lines: 3851cb0ef41Sopenharmony_ci if not self._first_write: 3861cb0ef41Sopenharmony_ci self.stream.write('\n' * self._new_lines) 3871cb0ef41Sopenharmony_ci self.code_lineno += self._new_lines 3881cb0ef41Sopenharmony_ci if self._write_debug_info is not None: 3891cb0ef41Sopenharmony_ci self.debug_info.append((self._write_debug_info, 3901cb0ef41Sopenharmony_ci self.code_lineno)) 3911cb0ef41Sopenharmony_ci self._write_debug_info = None 3921cb0ef41Sopenharmony_ci self._first_write = False 3931cb0ef41Sopenharmony_ci self.stream.write(' ' * self._indentation) 3941cb0ef41Sopenharmony_ci self._new_lines = 0 3951cb0ef41Sopenharmony_ci self.stream.write(x) 3961cb0ef41Sopenharmony_ci 3971cb0ef41Sopenharmony_ci def writeline(self, x, node=None, extra=0): 3981cb0ef41Sopenharmony_ci """Combination of newline and write.""" 3991cb0ef41Sopenharmony_ci self.newline(node, extra) 4001cb0ef41Sopenharmony_ci self.write(x) 4011cb0ef41Sopenharmony_ci 4021cb0ef41Sopenharmony_ci def newline(self, node=None, extra=0): 4031cb0ef41Sopenharmony_ci """Add one or more newlines before the next write.""" 4041cb0ef41Sopenharmony_ci self._new_lines = max(self._new_lines, 1 + extra) 4051cb0ef41Sopenharmony_ci if node is not None and node.lineno != self._last_line: 4061cb0ef41Sopenharmony_ci self._write_debug_info = node.lineno 4071cb0ef41Sopenharmony_ci self._last_line = node.lineno 4081cb0ef41Sopenharmony_ci 4091cb0ef41Sopenharmony_ci def signature(self, node, frame, extra_kwargs=None): 4101cb0ef41Sopenharmony_ci """Writes a function call to the stream for the current node. 4111cb0ef41Sopenharmony_ci A leading comma is added automatically. The extra keyword 4121cb0ef41Sopenharmony_ci arguments may not include python keywords otherwise a syntax 4131cb0ef41Sopenharmony_ci error could occour. The extra keyword arguments should be given 4141cb0ef41Sopenharmony_ci as python dict. 4151cb0ef41Sopenharmony_ci """ 4161cb0ef41Sopenharmony_ci # if any of the given keyword arguments is a python keyword 4171cb0ef41Sopenharmony_ci # we have to make sure that no invalid call is created. 4181cb0ef41Sopenharmony_ci kwarg_workaround = False 4191cb0ef41Sopenharmony_ci for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()): 4201cb0ef41Sopenharmony_ci if is_python_keyword(kwarg): 4211cb0ef41Sopenharmony_ci kwarg_workaround = True 4221cb0ef41Sopenharmony_ci break 4231cb0ef41Sopenharmony_ci 4241cb0ef41Sopenharmony_ci for arg in node.args: 4251cb0ef41Sopenharmony_ci self.write(', ') 4261cb0ef41Sopenharmony_ci self.visit(arg, frame) 4271cb0ef41Sopenharmony_ci 4281cb0ef41Sopenharmony_ci if not kwarg_workaround: 4291cb0ef41Sopenharmony_ci for kwarg in node.kwargs: 4301cb0ef41Sopenharmony_ci self.write(', ') 4311cb0ef41Sopenharmony_ci self.visit(kwarg, frame) 4321cb0ef41Sopenharmony_ci if extra_kwargs is not None: 4331cb0ef41Sopenharmony_ci for key, value in iteritems(extra_kwargs): 4341cb0ef41Sopenharmony_ci self.write(', %s=%s' % (key, value)) 4351cb0ef41Sopenharmony_ci if node.dyn_args: 4361cb0ef41Sopenharmony_ci self.write(', *') 4371cb0ef41Sopenharmony_ci self.visit(node.dyn_args, frame) 4381cb0ef41Sopenharmony_ci 4391cb0ef41Sopenharmony_ci if kwarg_workaround: 4401cb0ef41Sopenharmony_ci if node.dyn_kwargs is not None: 4411cb0ef41Sopenharmony_ci self.write(', **dict({') 4421cb0ef41Sopenharmony_ci else: 4431cb0ef41Sopenharmony_ci self.write(', **{') 4441cb0ef41Sopenharmony_ci for kwarg in node.kwargs: 4451cb0ef41Sopenharmony_ci self.write('%r: ' % kwarg.key) 4461cb0ef41Sopenharmony_ci self.visit(kwarg.value, frame) 4471cb0ef41Sopenharmony_ci self.write(', ') 4481cb0ef41Sopenharmony_ci if extra_kwargs is not None: 4491cb0ef41Sopenharmony_ci for key, value in iteritems(extra_kwargs): 4501cb0ef41Sopenharmony_ci self.write('%r: %s, ' % (key, value)) 4511cb0ef41Sopenharmony_ci if node.dyn_kwargs is not None: 4521cb0ef41Sopenharmony_ci self.write('}, **') 4531cb0ef41Sopenharmony_ci self.visit(node.dyn_kwargs, frame) 4541cb0ef41Sopenharmony_ci self.write(')') 4551cb0ef41Sopenharmony_ci else: 4561cb0ef41Sopenharmony_ci self.write('}') 4571cb0ef41Sopenharmony_ci 4581cb0ef41Sopenharmony_ci elif node.dyn_kwargs is not None: 4591cb0ef41Sopenharmony_ci self.write(', **') 4601cb0ef41Sopenharmony_ci self.visit(node.dyn_kwargs, frame) 4611cb0ef41Sopenharmony_ci 4621cb0ef41Sopenharmony_ci def pull_dependencies(self, nodes): 4631cb0ef41Sopenharmony_ci """Pull all the dependencies.""" 4641cb0ef41Sopenharmony_ci visitor = DependencyFinderVisitor() 4651cb0ef41Sopenharmony_ci for node in nodes: 4661cb0ef41Sopenharmony_ci visitor.visit(node) 4671cb0ef41Sopenharmony_ci for dependency in 'filters', 'tests': 4681cb0ef41Sopenharmony_ci mapping = getattr(self, dependency) 4691cb0ef41Sopenharmony_ci for name in getattr(visitor, dependency): 4701cb0ef41Sopenharmony_ci if name not in mapping: 4711cb0ef41Sopenharmony_ci mapping[name] = self.temporary_identifier() 4721cb0ef41Sopenharmony_ci self.writeline('%s = environment.%s[%r]' % 4731cb0ef41Sopenharmony_ci (mapping[name], dependency, name)) 4741cb0ef41Sopenharmony_ci 4751cb0ef41Sopenharmony_ci def enter_frame(self, frame): 4761cb0ef41Sopenharmony_ci undefs = [] 4771cb0ef41Sopenharmony_ci for target, (action, param) in iteritems(frame.symbols.loads): 4781cb0ef41Sopenharmony_ci if action == VAR_LOAD_PARAMETER: 4791cb0ef41Sopenharmony_ci pass 4801cb0ef41Sopenharmony_ci elif action == VAR_LOAD_RESOLVE: 4811cb0ef41Sopenharmony_ci self.writeline('%s = %s(%r)' % 4821cb0ef41Sopenharmony_ci (target, self.get_resolve_func(), param)) 4831cb0ef41Sopenharmony_ci elif action == VAR_LOAD_ALIAS: 4841cb0ef41Sopenharmony_ci self.writeline('%s = %s' % (target, param)) 4851cb0ef41Sopenharmony_ci elif action == VAR_LOAD_UNDEFINED: 4861cb0ef41Sopenharmony_ci undefs.append(target) 4871cb0ef41Sopenharmony_ci else: 4881cb0ef41Sopenharmony_ci raise NotImplementedError('unknown load instruction') 4891cb0ef41Sopenharmony_ci if undefs: 4901cb0ef41Sopenharmony_ci self.writeline('%s = missing' % ' = '.join(undefs)) 4911cb0ef41Sopenharmony_ci 4921cb0ef41Sopenharmony_ci def leave_frame(self, frame, with_python_scope=False): 4931cb0ef41Sopenharmony_ci if not with_python_scope: 4941cb0ef41Sopenharmony_ci undefs = [] 4951cb0ef41Sopenharmony_ci for target, _ in iteritems(frame.symbols.loads): 4961cb0ef41Sopenharmony_ci undefs.append(target) 4971cb0ef41Sopenharmony_ci if undefs: 4981cb0ef41Sopenharmony_ci self.writeline('%s = missing' % ' = '.join(undefs)) 4991cb0ef41Sopenharmony_ci 5001cb0ef41Sopenharmony_ci def func(self, name): 5011cb0ef41Sopenharmony_ci if self.environment.is_async: 5021cb0ef41Sopenharmony_ci return 'async def %s' % name 5031cb0ef41Sopenharmony_ci return 'def %s' % name 5041cb0ef41Sopenharmony_ci 5051cb0ef41Sopenharmony_ci def macro_body(self, node, frame): 5061cb0ef41Sopenharmony_ci """Dump the function def of a macro or call block.""" 5071cb0ef41Sopenharmony_ci frame = frame.inner() 5081cb0ef41Sopenharmony_ci frame.symbols.analyze_node(node) 5091cb0ef41Sopenharmony_ci macro_ref = MacroRef(node) 5101cb0ef41Sopenharmony_ci 5111cb0ef41Sopenharmony_ci explicit_caller = None 5121cb0ef41Sopenharmony_ci skip_special_params = set() 5131cb0ef41Sopenharmony_ci args = [] 5141cb0ef41Sopenharmony_ci for idx, arg in enumerate(node.args): 5151cb0ef41Sopenharmony_ci if arg.name == 'caller': 5161cb0ef41Sopenharmony_ci explicit_caller = idx 5171cb0ef41Sopenharmony_ci if arg.name in ('kwargs', 'varargs'): 5181cb0ef41Sopenharmony_ci skip_special_params.add(arg.name) 5191cb0ef41Sopenharmony_ci args.append(frame.symbols.ref(arg.name)) 5201cb0ef41Sopenharmony_ci 5211cb0ef41Sopenharmony_ci undeclared = find_undeclared(node.body, ('caller', 'kwargs', 'varargs')) 5221cb0ef41Sopenharmony_ci 5231cb0ef41Sopenharmony_ci if 'caller' in undeclared: 5241cb0ef41Sopenharmony_ci # In older Jinja2 versions there was a bug that allowed caller 5251cb0ef41Sopenharmony_ci # to retain the special behavior even if it was mentioned in 5261cb0ef41Sopenharmony_ci # the argument list. However thankfully this was only really 5271cb0ef41Sopenharmony_ci # working if it was the last argument. So we are explicitly 5281cb0ef41Sopenharmony_ci # checking this now and error out if it is anywhere else in 5291cb0ef41Sopenharmony_ci # the argument list. 5301cb0ef41Sopenharmony_ci if explicit_caller is not None: 5311cb0ef41Sopenharmony_ci try: 5321cb0ef41Sopenharmony_ci node.defaults[explicit_caller - len(node.args)] 5331cb0ef41Sopenharmony_ci except IndexError: 5341cb0ef41Sopenharmony_ci self.fail('When defining macros or call blocks the ' 5351cb0ef41Sopenharmony_ci 'special "caller" argument must be omitted ' 5361cb0ef41Sopenharmony_ci 'or be given a default.', node.lineno) 5371cb0ef41Sopenharmony_ci else: 5381cb0ef41Sopenharmony_ci args.append(frame.symbols.declare_parameter('caller')) 5391cb0ef41Sopenharmony_ci macro_ref.accesses_caller = True 5401cb0ef41Sopenharmony_ci if 'kwargs' in undeclared and not 'kwargs' in skip_special_params: 5411cb0ef41Sopenharmony_ci args.append(frame.symbols.declare_parameter('kwargs')) 5421cb0ef41Sopenharmony_ci macro_ref.accesses_kwargs = True 5431cb0ef41Sopenharmony_ci if 'varargs' in undeclared and not 'varargs' in skip_special_params: 5441cb0ef41Sopenharmony_ci args.append(frame.symbols.declare_parameter('varargs')) 5451cb0ef41Sopenharmony_ci macro_ref.accesses_varargs = True 5461cb0ef41Sopenharmony_ci 5471cb0ef41Sopenharmony_ci # macros are delayed, they never require output checks 5481cb0ef41Sopenharmony_ci frame.require_output_check = False 5491cb0ef41Sopenharmony_ci frame.symbols.analyze_node(node) 5501cb0ef41Sopenharmony_ci self.writeline('%s(%s):' % (self.func('macro'), ', '.join(args)), node) 5511cb0ef41Sopenharmony_ci self.indent() 5521cb0ef41Sopenharmony_ci 5531cb0ef41Sopenharmony_ci self.buffer(frame) 5541cb0ef41Sopenharmony_ci self.enter_frame(frame) 5551cb0ef41Sopenharmony_ci 5561cb0ef41Sopenharmony_ci self.push_parameter_definitions(frame) 5571cb0ef41Sopenharmony_ci for idx, arg in enumerate(node.args): 5581cb0ef41Sopenharmony_ci ref = frame.symbols.ref(arg.name) 5591cb0ef41Sopenharmony_ci self.writeline('if %s is missing:' % ref) 5601cb0ef41Sopenharmony_ci self.indent() 5611cb0ef41Sopenharmony_ci try: 5621cb0ef41Sopenharmony_ci default = node.defaults[idx - len(node.args)] 5631cb0ef41Sopenharmony_ci except IndexError: 5641cb0ef41Sopenharmony_ci self.writeline('%s = undefined(%r, name=%r)' % ( 5651cb0ef41Sopenharmony_ci ref, 5661cb0ef41Sopenharmony_ci 'parameter %r was not provided' % arg.name, 5671cb0ef41Sopenharmony_ci arg.name)) 5681cb0ef41Sopenharmony_ci else: 5691cb0ef41Sopenharmony_ci self.writeline('%s = ' % ref) 5701cb0ef41Sopenharmony_ci self.visit(default, frame) 5711cb0ef41Sopenharmony_ci self.mark_parameter_stored(ref) 5721cb0ef41Sopenharmony_ci self.outdent() 5731cb0ef41Sopenharmony_ci self.pop_parameter_definitions() 5741cb0ef41Sopenharmony_ci 5751cb0ef41Sopenharmony_ci self.blockvisit(node.body, frame) 5761cb0ef41Sopenharmony_ci self.return_buffer_contents(frame, force_unescaped=True) 5771cb0ef41Sopenharmony_ci self.leave_frame(frame, with_python_scope=True) 5781cb0ef41Sopenharmony_ci self.outdent() 5791cb0ef41Sopenharmony_ci 5801cb0ef41Sopenharmony_ci return frame, macro_ref 5811cb0ef41Sopenharmony_ci 5821cb0ef41Sopenharmony_ci def macro_def(self, macro_ref, frame): 5831cb0ef41Sopenharmony_ci """Dump the macro definition for the def created by macro_body.""" 5841cb0ef41Sopenharmony_ci arg_tuple = ', '.join(repr(x.name) for x in macro_ref.node.args) 5851cb0ef41Sopenharmony_ci name = getattr(macro_ref.node, 'name', None) 5861cb0ef41Sopenharmony_ci if len(macro_ref.node.args) == 1: 5871cb0ef41Sopenharmony_ci arg_tuple += ',' 5881cb0ef41Sopenharmony_ci self.write('Macro(environment, macro, %r, (%s), %r, %r, %r, ' 5891cb0ef41Sopenharmony_ci 'context.eval_ctx.autoescape)' % 5901cb0ef41Sopenharmony_ci (name, arg_tuple, macro_ref.accesses_kwargs, 5911cb0ef41Sopenharmony_ci macro_ref.accesses_varargs, macro_ref.accesses_caller)) 5921cb0ef41Sopenharmony_ci 5931cb0ef41Sopenharmony_ci def position(self, node): 5941cb0ef41Sopenharmony_ci """Return a human readable position for the node.""" 5951cb0ef41Sopenharmony_ci rv = 'line %d' % node.lineno 5961cb0ef41Sopenharmony_ci if self.name is not None: 5971cb0ef41Sopenharmony_ci rv += ' in ' + repr(self.name) 5981cb0ef41Sopenharmony_ci return rv 5991cb0ef41Sopenharmony_ci 6001cb0ef41Sopenharmony_ci def dump_local_context(self, frame): 6011cb0ef41Sopenharmony_ci return '{%s}' % ', '.join( 6021cb0ef41Sopenharmony_ci '%r: %s' % (name, target) for name, target 6031cb0ef41Sopenharmony_ci in iteritems(frame.symbols.dump_stores())) 6041cb0ef41Sopenharmony_ci 6051cb0ef41Sopenharmony_ci def write_commons(self): 6061cb0ef41Sopenharmony_ci """Writes a common preamble that is used by root and block functions. 6071cb0ef41Sopenharmony_ci Primarily this sets up common local helpers and enforces a generator 6081cb0ef41Sopenharmony_ci through a dead branch. 6091cb0ef41Sopenharmony_ci """ 6101cb0ef41Sopenharmony_ci self.writeline('resolve = context.resolve_or_missing') 6111cb0ef41Sopenharmony_ci self.writeline('undefined = environment.undefined') 6121cb0ef41Sopenharmony_ci self.writeline('if 0: yield None') 6131cb0ef41Sopenharmony_ci 6141cb0ef41Sopenharmony_ci def push_parameter_definitions(self, frame): 6151cb0ef41Sopenharmony_ci """Pushes all parameter targets from the given frame into a local 6161cb0ef41Sopenharmony_ci stack that permits tracking of yet to be assigned parameters. In 6171cb0ef41Sopenharmony_ci particular this enables the optimization from `visit_Name` to skip 6181cb0ef41Sopenharmony_ci undefined expressions for parameters in macros as macros can reference 6191cb0ef41Sopenharmony_ci otherwise unbound parameters. 6201cb0ef41Sopenharmony_ci """ 6211cb0ef41Sopenharmony_ci self._param_def_block.append(frame.symbols.dump_param_targets()) 6221cb0ef41Sopenharmony_ci 6231cb0ef41Sopenharmony_ci def pop_parameter_definitions(self): 6241cb0ef41Sopenharmony_ci """Pops the current parameter definitions set.""" 6251cb0ef41Sopenharmony_ci self._param_def_block.pop() 6261cb0ef41Sopenharmony_ci 6271cb0ef41Sopenharmony_ci def mark_parameter_stored(self, target): 6281cb0ef41Sopenharmony_ci """Marks a parameter in the current parameter definitions as stored. 6291cb0ef41Sopenharmony_ci This will skip the enforced undefined checks. 6301cb0ef41Sopenharmony_ci """ 6311cb0ef41Sopenharmony_ci if self._param_def_block: 6321cb0ef41Sopenharmony_ci self._param_def_block[-1].discard(target) 6331cb0ef41Sopenharmony_ci 6341cb0ef41Sopenharmony_ci def push_context_reference(self, target): 6351cb0ef41Sopenharmony_ci self._context_reference_stack.append(target) 6361cb0ef41Sopenharmony_ci 6371cb0ef41Sopenharmony_ci def pop_context_reference(self): 6381cb0ef41Sopenharmony_ci self._context_reference_stack.pop() 6391cb0ef41Sopenharmony_ci 6401cb0ef41Sopenharmony_ci def get_context_ref(self): 6411cb0ef41Sopenharmony_ci return self._context_reference_stack[-1] 6421cb0ef41Sopenharmony_ci 6431cb0ef41Sopenharmony_ci def get_resolve_func(self): 6441cb0ef41Sopenharmony_ci target = self._context_reference_stack[-1] 6451cb0ef41Sopenharmony_ci if target == 'context': 6461cb0ef41Sopenharmony_ci return 'resolve' 6471cb0ef41Sopenharmony_ci return '%s.resolve' % target 6481cb0ef41Sopenharmony_ci 6491cb0ef41Sopenharmony_ci def derive_context(self, frame): 6501cb0ef41Sopenharmony_ci return '%s.derived(%s)' % ( 6511cb0ef41Sopenharmony_ci self.get_context_ref(), 6521cb0ef41Sopenharmony_ci self.dump_local_context(frame), 6531cb0ef41Sopenharmony_ci ) 6541cb0ef41Sopenharmony_ci 6551cb0ef41Sopenharmony_ci def parameter_is_undeclared(self, target): 6561cb0ef41Sopenharmony_ci """Checks if a given target is an undeclared parameter.""" 6571cb0ef41Sopenharmony_ci if not self._param_def_block: 6581cb0ef41Sopenharmony_ci return False 6591cb0ef41Sopenharmony_ci return target in self._param_def_block[-1] 6601cb0ef41Sopenharmony_ci 6611cb0ef41Sopenharmony_ci def push_assign_tracking(self): 6621cb0ef41Sopenharmony_ci """Pushes a new layer for assignment tracking.""" 6631cb0ef41Sopenharmony_ci self._assign_stack.append(set()) 6641cb0ef41Sopenharmony_ci 6651cb0ef41Sopenharmony_ci def pop_assign_tracking(self, frame): 6661cb0ef41Sopenharmony_ci """Pops the topmost level for assignment tracking and updates the 6671cb0ef41Sopenharmony_ci context variables if necessary. 6681cb0ef41Sopenharmony_ci """ 6691cb0ef41Sopenharmony_ci vars = self._assign_stack.pop() 6701cb0ef41Sopenharmony_ci if not frame.toplevel or not vars: 6711cb0ef41Sopenharmony_ci return 6721cb0ef41Sopenharmony_ci public_names = [x for x in vars if x[:1] != '_'] 6731cb0ef41Sopenharmony_ci if len(vars) == 1: 6741cb0ef41Sopenharmony_ci name = next(iter(vars)) 6751cb0ef41Sopenharmony_ci ref = frame.symbols.ref(name) 6761cb0ef41Sopenharmony_ci self.writeline('context.vars[%r] = %s' % (name, ref)) 6771cb0ef41Sopenharmony_ci else: 6781cb0ef41Sopenharmony_ci self.writeline('context.vars.update({') 6791cb0ef41Sopenharmony_ci for idx, name in enumerate(vars): 6801cb0ef41Sopenharmony_ci if idx: 6811cb0ef41Sopenharmony_ci self.write(', ') 6821cb0ef41Sopenharmony_ci ref = frame.symbols.ref(name) 6831cb0ef41Sopenharmony_ci self.write('%r: %s' % (name, ref)) 6841cb0ef41Sopenharmony_ci self.write('})') 6851cb0ef41Sopenharmony_ci if public_names: 6861cb0ef41Sopenharmony_ci if len(public_names) == 1: 6871cb0ef41Sopenharmony_ci self.writeline('context.exported_vars.add(%r)' % 6881cb0ef41Sopenharmony_ci public_names[0]) 6891cb0ef41Sopenharmony_ci else: 6901cb0ef41Sopenharmony_ci self.writeline('context.exported_vars.update((%s))' % 6911cb0ef41Sopenharmony_ci ', '.join(imap(repr, public_names))) 6921cb0ef41Sopenharmony_ci 6931cb0ef41Sopenharmony_ci # -- Statement Visitors 6941cb0ef41Sopenharmony_ci 6951cb0ef41Sopenharmony_ci def visit_Template(self, node, frame=None): 6961cb0ef41Sopenharmony_ci assert frame is None, 'no root frame allowed' 6971cb0ef41Sopenharmony_ci eval_ctx = EvalContext(self.environment, self.name) 6981cb0ef41Sopenharmony_ci 6991cb0ef41Sopenharmony_ci from jinja2.runtime import __all__ as exported 7001cb0ef41Sopenharmony_ci self.writeline('from __future__ import %s' % ', '.join(code_features)) 7011cb0ef41Sopenharmony_ci self.writeline('from jinja2.runtime import ' + ', '.join(exported)) 7021cb0ef41Sopenharmony_ci 7031cb0ef41Sopenharmony_ci if self.environment.is_async: 7041cb0ef41Sopenharmony_ci self.writeline('from jinja2.asyncsupport import auto_await, ' 7051cb0ef41Sopenharmony_ci 'auto_aiter, make_async_loop_context') 7061cb0ef41Sopenharmony_ci 7071cb0ef41Sopenharmony_ci # if we want a deferred initialization we cannot move the 7081cb0ef41Sopenharmony_ci # environment into a local name 7091cb0ef41Sopenharmony_ci envenv = not self.defer_init and ', environment=environment' or '' 7101cb0ef41Sopenharmony_ci 7111cb0ef41Sopenharmony_ci # do we have an extends tag at all? If not, we can save some 7121cb0ef41Sopenharmony_ci # overhead by just not processing any inheritance code. 7131cb0ef41Sopenharmony_ci have_extends = node.find(nodes.Extends) is not None 7141cb0ef41Sopenharmony_ci 7151cb0ef41Sopenharmony_ci # find all blocks 7161cb0ef41Sopenharmony_ci for block in node.find_all(nodes.Block): 7171cb0ef41Sopenharmony_ci if block.name in self.blocks: 7181cb0ef41Sopenharmony_ci self.fail('block %r defined twice' % block.name, block.lineno) 7191cb0ef41Sopenharmony_ci self.blocks[block.name] = block 7201cb0ef41Sopenharmony_ci 7211cb0ef41Sopenharmony_ci # find all imports and import them 7221cb0ef41Sopenharmony_ci for import_ in node.find_all(nodes.ImportedName): 7231cb0ef41Sopenharmony_ci if import_.importname not in self.import_aliases: 7241cb0ef41Sopenharmony_ci imp = import_.importname 7251cb0ef41Sopenharmony_ci self.import_aliases[imp] = alias = self.temporary_identifier() 7261cb0ef41Sopenharmony_ci if '.' in imp: 7271cb0ef41Sopenharmony_ci module, obj = imp.rsplit('.', 1) 7281cb0ef41Sopenharmony_ci self.writeline('from %s import %s as %s' % 7291cb0ef41Sopenharmony_ci (module, obj, alias)) 7301cb0ef41Sopenharmony_ci else: 7311cb0ef41Sopenharmony_ci self.writeline('import %s as %s' % (imp, alias)) 7321cb0ef41Sopenharmony_ci 7331cb0ef41Sopenharmony_ci # add the load name 7341cb0ef41Sopenharmony_ci self.writeline('name = %r' % self.name) 7351cb0ef41Sopenharmony_ci 7361cb0ef41Sopenharmony_ci # generate the root render function. 7371cb0ef41Sopenharmony_ci self.writeline('%s(context, missing=missing%s):' % 7381cb0ef41Sopenharmony_ci (self.func('root'), envenv), extra=1) 7391cb0ef41Sopenharmony_ci self.indent() 7401cb0ef41Sopenharmony_ci self.write_commons() 7411cb0ef41Sopenharmony_ci 7421cb0ef41Sopenharmony_ci # process the root 7431cb0ef41Sopenharmony_ci frame = Frame(eval_ctx) 7441cb0ef41Sopenharmony_ci if 'self' in find_undeclared(node.body, ('self',)): 7451cb0ef41Sopenharmony_ci ref = frame.symbols.declare_parameter('self') 7461cb0ef41Sopenharmony_ci self.writeline('%s = TemplateReference(context)' % ref) 7471cb0ef41Sopenharmony_ci frame.symbols.analyze_node(node) 7481cb0ef41Sopenharmony_ci frame.toplevel = frame.rootlevel = True 7491cb0ef41Sopenharmony_ci frame.require_output_check = have_extends and not self.has_known_extends 7501cb0ef41Sopenharmony_ci if have_extends: 7511cb0ef41Sopenharmony_ci self.writeline('parent_template = None') 7521cb0ef41Sopenharmony_ci self.enter_frame(frame) 7531cb0ef41Sopenharmony_ci self.pull_dependencies(node.body) 7541cb0ef41Sopenharmony_ci self.blockvisit(node.body, frame) 7551cb0ef41Sopenharmony_ci self.leave_frame(frame, with_python_scope=True) 7561cb0ef41Sopenharmony_ci self.outdent() 7571cb0ef41Sopenharmony_ci 7581cb0ef41Sopenharmony_ci # make sure that the parent root is called. 7591cb0ef41Sopenharmony_ci if have_extends: 7601cb0ef41Sopenharmony_ci if not self.has_known_extends: 7611cb0ef41Sopenharmony_ci self.indent() 7621cb0ef41Sopenharmony_ci self.writeline('if parent_template is not None:') 7631cb0ef41Sopenharmony_ci self.indent() 7641cb0ef41Sopenharmony_ci if supports_yield_from and not self.environment.is_async: 7651cb0ef41Sopenharmony_ci self.writeline('yield from parent_template.' 7661cb0ef41Sopenharmony_ci 'root_render_func(context)') 7671cb0ef41Sopenharmony_ci else: 7681cb0ef41Sopenharmony_ci self.writeline('%sfor event in parent_template.' 7691cb0ef41Sopenharmony_ci 'root_render_func(context):' % 7701cb0ef41Sopenharmony_ci (self.environment.is_async and 'async ' or '')) 7711cb0ef41Sopenharmony_ci self.indent() 7721cb0ef41Sopenharmony_ci self.writeline('yield event') 7731cb0ef41Sopenharmony_ci self.outdent() 7741cb0ef41Sopenharmony_ci self.outdent(1 + (not self.has_known_extends)) 7751cb0ef41Sopenharmony_ci 7761cb0ef41Sopenharmony_ci # at this point we now have the blocks collected and can visit them too. 7771cb0ef41Sopenharmony_ci for name, block in iteritems(self.blocks): 7781cb0ef41Sopenharmony_ci self.writeline('%s(context, missing=missing%s):' % 7791cb0ef41Sopenharmony_ci (self.func('block_' + name), envenv), 7801cb0ef41Sopenharmony_ci block, 1) 7811cb0ef41Sopenharmony_ci self.indent() 7821cb0ef41Sopenharmony_ci self.write_commons() 7831cb0ef41Sopenharmony_ci # It's important that we do not make this frame a child of the 7841cb0ef41Sopenharmony_ci # toplevel template. This would cause a variety of 7851cb0ef41Sopenharmony_ci # interesting issues with identifier tracking. 7861cb0ef41Sopenharmony_ci block_frame = Frame(eval_ctx) 7871cb0ef41Sopenharmony_ci undeclared = find_undeclared(block.body, ('self', 'super')) 7881cb0ef41Sopenharmony_ci if 'self' in undeclared: 7891cb0ef41Sopenharmony_ci ref = block_frame.symbols.declare_parameter('self') 7901cb0ef41Sopenharmony_ci self.writeline('%s = TemplateReference(context)' % ref) 7911cb0ef41Sopenharmony_ci if 'super' in undeclared: 7921cb0ef41Sopenharmony_ci ref = block_frame.symbols.declare_parameter('super') 7931cb0ef41Sopenharmony_ci self.writeline('%s = context.super(%r, ' 7941cb0ef41Sopenharmony_ci 'block_%s)' % (ref, name, name)) 7951cb0ef41Sopenharmony_ci block_frame.symbols.analyze_node(block) 7961cb0ef41Sopenharmony_ci block_frame.block = name 7971cb0ef41Sopenharmony_ci self.enter_frame(block_frame) 7981cb0ef41Sopenharmony_ci self.pull_dependencies(block.body) 7991cb0ef41Sopenharmony_ci self.blockvisit(block.body, block_frame) 8001cb0ef41Sopenharmony_ci self.leave_frame(block_frame, with_python_scope=True) 8011cb0ef41Sopenharmony_ci self.outdent() 8021cb0ef41Sopenharmony_ci 8031cb0ef41Sopenharmony_ci self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x) 8041cb0ef41Sopenharmony_ci for x in self.blocks), 8051cb0ef41Sopenharmony_ci extra=1) 8061cb0ef41Sopenharmony_ci 8071cb0ef41Sopenharmony_ci # add a function that returns the debug info 8081cb0ef41Sopenharmony_ci self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x 8091cb0ef41Sopenharmony_ci in self.debug_info)) 8101cb0ef41Sopenharmony_ci 8111cb0ef41Sopenharmony_ci def visit_Block(self, node, frame): 8121cb0ef41Sopenharmony_ci """Call a block and register it for the template.""" 8131cb0ef41Sopenharmony_ci level = 0 8141cb0ef41Sopenharmony_ci if frame.toplevel: 8151cb0ef41Sopenharmony_ci # if we know that we are a child template, there is no need to 8161cb0ef41Sopenharmony_ci # check if we are one 8171cb0ef41Sopenharmony_ci if self.has_known_extends: 8181cb0ef41Sopenharmony_ci return 8191cb0ef41Sopenharmony_ci if self.extends_so_far > 0: 8201cb0ef41Sopenharmony_ci self.writeline('if parent_template is None:') 8211cb0ef41Sopenharmony_ci self.indent() 8221cb0ef41Sopenharmony_ci level += 1 8231cb0ef41Sopenharmony_ci 8241cb0ef41Sopenharmony_ci if node.scoped: 8251cb0ef41Sopenharmony_ci context = self.derive_context(frame) 8261cb0ef41Sopenharmony_ci else: 8271cb0ef41Sopenharmony_ci context = self.get_context_ref() 8281cb0ef41Sopenharmony_ci 8291cb0ef41Sopenharmony_ci if supports_yield_from and not self.environment.is_async and \ 8301cb0ef41Sopenharmony_ci frame.buffer is None: 8311cb0ef41Sopenharmony_ci self.writeline('yield from context.blocks[%r][0](%s)' % ( 8321cb0ef41Sopenharmony_ci node.name, context), node) 8331cb0ef41Sopenharmony_ci else: 8341cb0ef41Sopenharmony_ci loop = self.environment.is_async and 'async for' or 'for' 8351cb0ef41Sopenharmony_ci self.writeline('%s event in context.blocks[%r][0](%s):' % ( 8361cb0ef41Sopenharmony_ci loop, node.name, context), node) 8371cb0ef41Sopenharmony_ci self.indent() 8381cb0ef41Sopenharmony_ci self.simple_write('event', frame) 8391cb0ef41Sopenharmony_ci self.outdent() 8401cb0ef41Sopenharmony_ci 8411cb0ef41Sopenharmony_ci self.outdent(level) 8421cb0ef41Sopenharmony_ci 8431cb0ef41Sopenharmony_ci def visit_Extends(self, node, frame): 8441cb0ef41Sopenharmony_ci """Calls the extender.""" 8451cb0ef41Sopenharmony_ci if not frame.toplevel: 8461cb0ef41Sopenharmony_ci self.fail('cannot use extend from a non top-level scope', 8471cb0ef41Sopenharmony_ci node.lineno) 8481cb0ef41Sopenharmony_ci 8491cb0ef41Sopenharmony_ci # if the number of extends statements in general is zero so 8501cb0ef41Sopenharmony_ci # far, we don't have to add a check if something extended 8511cb0ef41Sopenharmony_ci # the template before this one. 8521cb0ef41Sopenharmony_ci if self.extends_so_far > 0: 8531cb0ef41Sopenharmony_ci 8541cb0ef41Sopenharmony_ci # if we have a known extends we just add a template runtime 8551cb0ef41Sopenharmony_ci # error into the generated code. We could catch that at compile 8561cb0ef41Sopenharmony_ci # time too, but i welcome it not to confuse users by throwing the 8571cb0ef41Sopenharmony_ci # same error at different times just "because we can". 8581cb0ef41Sopenharmony_ci if not self.has_known_extends: 8591cb0ef41Sopenharmony_ci self.writeline('if parent_template is not None:') 8601cb0ef41Sopenharmony_ci self.indent() 8611cb0ef41Sopenharmony_ci self.writeline('raise TemplateRuntimeError(%r)' % 8621cb0ef41Sopenharmony_ci 'extended multiple times') 8631cb0ef41Sopenharmony_ci 8641cb0ef41Sopenharmony_ci # if we have a known extends already we don't need that code here 8651cb0ef41Sopenharmony_ci # as we know that the template execution will end here. 8661cb0ef41Sopenharmony_ci if self.has_known_extends: 8671cb0ef41Sopenharmony_ci raise CompilerExit() 8681cb0ef41Sopenharmony_ci else: 8691cb0ef41Sopenharmony_ci self.outdent() 8701cb0ef41Sopenharmony_ci 8711cb0ef41Sopenharmony_ci self.writeline('parent_template = environment.get_template(', node) 8721cb0ef41Sopenharmony_ci self.visit(node.template, frame) 8731cb0ef41Sopenharmony_ci self.write(', %r)' % self.name) 8741cb0ef41Sopenharmony_ci self.writeline('for name, parent_block in parent_template.' 8751cb0ef41Sopenharmony_ci 'blocks.%s():' % dict_item_iter) 8761cb0ef41Sopenharmony_ci self.indent() 8771cb0ef41Sopenharmony_ci self.writeline('context.blocks.setdefault(name, []).' 8781cb0ef41Sopenharmony_ci 'append(parent_block)') 8791cb0ef41Sopenharmony_ci self.outdent() 8801cb0ef41Sopenharmony_ci 8811cb0ef41Sopenharmony_ci # if this extends statement was in the root level we can take 8821cb0ef41Sopenharmony_ci # advantage of that information and simplify the generated code 8831cb0ef41Sopenharmony_ci # in the top level from this point onwards 8841cb0ef41Sopenharmony_ci if frame.rootlevel: 8851cb0ef41Sopenharmony_ci self.has_known_extends = True 8861cb0ef41Sopenharmony_ci 8871cb0ef41Sopenharmony_ci # and now we have one more 8881cb0ef41Sopenharmony_ci self.extends_so_far += 1 8891cb0ef41Sopenharmony_ci 8901cb0ef41Sopenharmony_ci def visit_Include(self, node, frame): 8911cb0ef41Sopenharmony_ci """Handles includes.""" 8921cb0ef41Sopenharmony_ci if node.ignore_missing: 8931cb0ef41Sopenharmony_ci self.writeline('try:') 8941cb0ef41Sopenharmony_ci self.indent() 8951cb0ef41Sopenharmony_ci 8961cb0ef41Sopenharmony_ci func_name = 'get_or_select_template' 8971cb0ef41Sopenharmony_ci if isinstance(node.template, nodes.Const): 8981cb0ef41Sopenharmony_ci if isinstance(node.template.value, string_types): 8991cb0ef41Sopenharmony_ci func_name = 'get_template' 9001cb0ef41Sopenharmony_ci elif isinstance(node.template.value, (tuple, list)): 9011cb0ef41Sopenharmony_ci func_name = 'select_template' 9021cb0ef41Sopenharmony_ci elif isinstance(node.template, (nodes.Tuple, nodes.List)): 9031cb0ef41Sopenharmony_ci func_name = 'select_template' 9041cb0ef41Sopenharmony_ci 9051cb0ef41Sopenharmony_ci self.writeline('template = environment.%s(' % func_name, node) 9061cb0ef41Sopenharmony_ci self.visit(node.template, frame) 9071cb0ef41Sopenharmony_ci self.write(', %r)' % self.name) 9081cb0ef41Sopenharmony_ci if node.ignore_missing: 9091cb0ef41Sopenharmony_ci self.outdent() 9101cb0ef41Sopenharmony_ci self.writeline('except TemplateNotFound:') 9111cb0ef41Sopenharmony_ci self.indent() 9121cb0ef41Sopenharmony_ci self.writeline('pass') 9131cb0ef41Sopenharmony_ci self.outdent() 9141cb0ef41Sopenharmony_ci self.writeline('else:') 9151cb0ef41Sopenharmony_ci self.indent() 9161cb0ef41Sopenharmony_ci 9171cb0ef41Sopenharmony_ci skip_event_yield = False 9181cb0ef41Sopenharmony_ci if node.with_context: 9191cb0ef41Sopenharmony_ci loop = self.environment.is_async and 'async for' or 'for' 9201cb0ef41Sopenharmony_ci self.writeline('%s event in template.root_render_func(' 9211cb0ef41Sopenharmony_ci 'template.new_context(context.get_all(), True, ' 9221cb0ef41Sopenharmony_ci '%s)):' % (loop, self.dump_local_context(frame))) 9231cb0ef41Sopenharmony_ci elif self.environment.is_async: 9241cb0ef41Sopenharmony_ci self.writeline('for event in (await ' 9251cb0ef41Sopenharmony_ci 'template._get_default_module_async())' 9261cb0ef41Sopenharmony_ci '._body_stream:') 9271cb0ef41Sopenharmony_ci else: 9281cb0ef41Sopenharmony_ci if supports_yield_from: 9291cb0ef41Sopenharmony_ci self.writeline('yield from template._get_default_module()' 9301cb0ef41Sopenharmony_ci '._body_stream') 9311cb0ef41Sopenharmony_ci skip_event_yield = True 9321cb0ef41Sopenharmony_ci else: 9331cb0ef41Sopenharmony_ci self.writeline('for event in template._get_default_module()' 9341cb0ef41Sopenharmony_ci '._body_stream:') 9351cb0ef41Sopenharmony_ci 9361cb0ef41Sopenharmony_ci if not skip_event_yield: 9371cb0ef41Sopenharmony_ci self.indent() 9381cb0ef41Sopenharmony_ci self.simple_write('event', frame) 9391cb0ef41Sopenharmony_ci self.outdent() 9401cb0ef41Sopenharmony_ci 9411cb0ef41Sopenharmony_ci if node.ignore_missing: 9421cb0ef41Sopenharmony_ci self.outdent() 9431cb0ef41Sopenharmony_ci 9441cb0ef41Sopenharmony_ci def visit_Import(self, node, frame): 9451cb0ef41Sopenharmony_ci """Visit regular imports.""" 9461cb0ef41Sopenharmony_ci self.writeline('%s = ' % frame.symbols.ref(node.target), node) 9471cb0ef41Sopenharmony_ci if frame.toplevel: 9481cb0ef41Sopenharmony_ci self.write('context.vars[%r] = ' % node.target) 9491cb0ef41Sopenharmony_ci if self.environment.is_async: 9501cb0ef41Sopenharmony_ci self.write('await ') 9511cb0ef41Sopenharmony_ci self.write('environment.get_template(') 9521cb0ef41Sopenharmony_ci self.visit(node.template, frame) 9531cb0ef41Sopenharmony_ci self.write(', %r).' % self.name) 9541cb0ef41Sopenharmony_ci if node.with_context: 9551cb0ef41Sopenharmony_ci self.write('make_module%s(context.get_all(), True, %s)' 9561cb0ef41Sopenharmony_ci % (self.environment.is_async and '_async' or '', 9571cb0ef41Sopenharmony_ci self.dump_local_context(frame))) 9581cb0ef41Sopenharmony_ci elif self.environment.is_async: 9591cb0ef41Sopenharmony_ci self.write('_get_default_module_async()') 9601cb0ef41Sopenharmony_ci else: 9611cb0ef41Sopenharmony_ci self.write('_get_default_module()') 9621cb0ef41Sopenharmony_ci if frame.toplevel and not node.target.startswith('_'): 9631cb0ef41Sopenharmony_ci self.writeline('context.exported_vars.discard(%r)' % node.target) 9641cb0ef41Sopenharmony_ci 9651cb0ef41Sopenharmony_ci def visit_FromImport(self, node, frame): 9661cb0ef41Sopenharmony_ci """Visit named imports.""" 9671cb0ef41Sopenharmony_ci self.newline(node) 9681cb0ef41Sopenharmony_ci self.write('included_template = %senvironment.get_template(' 9691cb0ef41Sopenharmony_ci % (self.environment.is_async and 'await ' or '')) 9701cb0ef41Sopenharmony_ci self.visit(node.template, frame) 9711cb0ef41Sopenharmony_ci self.write(', %r).' % self.name) 9721cb0ef41Sopenharmony_ci if node.with_context: 9731cb0ef41Sopenharmony_ci self.write('make_module%s(context.get_all(), True, %s)' 9741cb0ef41Sopenharmony_ci % (self.environment.is_async and '_async' or '', 9751cb0ef41Sopenharmony_ci self.dump_local_context(frame))) 9761cb0ef41Sopenharmony_ci elif self.environment.is_async: 9771cb0ef41Sopenharmony_ci self.write('_get_default_module_async()') 9781cb0ef41Sopenharmony_ci else: 9791cb0ef41Sopenharmony_ci self.write('_get_default_module()') 9801cb0ef41Sopenharmony_ci 9811cb0ef41Sopenharmony_ci var_names = [] 9821cb0ef41Sopenharmony_ci discarded_names = [] 9831cb0ef41Sopenharmony_ci for name in node.names: 9841cb0ef41Sopenharmony_ci if isinstance(name, tuple): 9851cb0ef41Sopenharmony_ci name, alias = name 9861cb0ef41Sopenharmony_ci else: 9871cb0ef41Sopenharmony_ci alias = name 9881cb0ef41Sopenharmony_ci self.writeline('%s = getattr(included_template, ' 9891cb0ef41Sopenharmony_ci '%r, missing)' % (frame.symbols.ref(alias), name)) 9901cb0ef41Sopenharmony_ci self.writeline('if %s is missing:' % frame.symbols.ref(alias)) 9911cb0ef41Sopenharmony_ci self.indent() 9921cb0ef41Sopenharmony_ci self.writeline('%s = undefined(%r %% ' 9931cb0ef41Sopenharmony_ci 'included_template.__name__, ' 9941cb0ef41Sopenharmony_ci 'name=%r)' % 9951cb0ef41Sopenharmony_ci (frame.symbols.ref(alias), 9961cb0ef41Sopenharmony_ci 'the template %%r (imported on %s) does ' 9971cb0ef41Sopenharmony_ci 'not export the requested name %s' % ( 9981cb0ef41Sopenharmony_ci self.position(node), 9991cb0ef41Sopenharmony_ci repr(name) 10001cb0ef41Sopenharmony_ci ), name)) 10011cb0ef41Sopenharmony_ci self.outdent() 10021cb0ef41Sopenharmony_ci if frame.toplevel: 10031cb0ef41Sopenharmony_ci var_names.append(alias) 10041cb0ef41Sopenharmony_ci if not alias.startswith('_'): 10051cb0ef41Sopenharmony_ci discarded_names.append(alias) 10061cb0ef41Sopenharmony_ci 10071cb0ef41Sopenharmony_ci if var_names: 10081cb0ef41Sopenharmony_ci if len(var_names) == 1: 10091cb0ef41Sopenharmony_ci name = var_names[0] 10101cb0ef41Sopenharmony_ci self.writeline('context.vars[%r] = %s' % 10111cb0ef41Sopenharmony_ci (name, frame.symbols.ref(name))) 10121cb0ef41Sopenharmony_ci else: 10131cb0ef41Sopenharmony_ci self.writeline('context.vars.update({%s})' % ', '.join( 10141cb0ef41Sopenharmony_ci '%r: %s' % (name, frame.symbols.ref(name)) for name in var_names 10151cb0ef41Sopenharmony_ci )) 10161cb0ef41Sopenharmony_ci if discarded_names: 10171cb0ef41Sopenharmony_ci if len(discarded_names) == 1: 10181cb0ef41Sopenharmony_ci self.writeline('context.exported_vars.discard(%r)' % 10191cb0ef41Sopenharmony_ci discarded_names[0]) 10201cb0ef41Sopenharmony_ci else: 10211cb0ef41Sopenharmony_ci self.writeline('context.exported_vars.difference_' 10221cb0ef41Sopenharmony_ci 'update((%s))' % ', '.join(imap(repr, discarded_names))) 10231cb0ef41Sopenharmony_ci 10241cb0ef41Sopenharmony_ci def visit_For(self, node, frame): 10251cb0ef41Sopenharmony_ci loop_frame = frame.inner() 10261cb0ef41Sopenharmony_ci test_frame = frame.inner() 10271cb0ef41Sopenharmony_ci else_frame = frame.inner() 10281cb0ef41Sopenharmony_ci 10291cb0ef41Sopenharmony_ci # try to figure out if we have an extended loop. An extended loop 10301cb0ef41Sopenharmony_ci # is necessary if the loop is in recursive mode if the special loop 10311cb0ef41Sopenharmony_ci # variable is accessed in the body. 10321cb0ef41Sopenharmony_ci extended_loop = node.recursive or 'loop' in \ 10331cb0ef41Sopenharmony_ci find_undeclared(node.iter_child_nodes( 10341cb0ef41Sopenharmony_ci only=('body',)), ('loop',)) 10351cb0ef41Sopenharmony_ci 10361cb0ef41Sopenharmony_ci loop_ref = None 10371cb0ef41Sopenharmony_ci if extended_loop: 10381cb0ef41Sopenharmony_ci loop_ref = loop_frame.symbols.declare_parameter('loop') 10391cb0ef41Sopenharmony_ci 10401cb0ef41Sopenharmony_ci loop_frame.symbols.analyze_node(node, for_branch='body') 10411cb0ef41Sopenharmony_ci if node.else_: 10421cb0ef41Sopenharmony_ci else_frame.symbols.analyze_node(node, for_branch='else') 10431cb0ef41Sopenharmony_ci 10441cb0ef41Sopenharmony_ci if node.test: 10451cb0ef41Sopenharmony_ci loop_filter_func = self.temporary_identifier() 10461cb0ef41Sopenharmony_ci test_frame.symbols.analyze_node(node, for_branch='test') 10471cb0ef41Sopenharmony_ci self.writeline('%s(fiter):' % self.func(loop_filter_func), node.test) 10481cb0ef41Sopenharmony_ci self.indent() 10491cb0ef41Sopenharmony_ci self.enter_frame(test_frame) 10501cb0ef41Sopenharmony_ci self.writeline(self.environment.is_async and 'async for ' or 'for ') 10511cb0ef41Sopenharmony_ci self.visit(node.target, loop_frame) 10521cb0ef41Sopenharmony_ci self.write(' in ') 10531cb0ef41Sopenharmony_ci self.write(self.environment.is_async and 'auto_aiter(fiter)' or 'fiter') 10541cb0ef41Sopenharmony_ci self.write(':') 10551cb0ef41Sopenharmony_ci self.indent() 10561cb0ef41Sopenharmony_ci self.writeline('if ', node.test) 10571cb0ef41Sopenharmony_ci self.visit(node.test, test_frame) 10581cb0ef41Sopenharmony_ci self.write(':') 10591cb0ef41Sopenharmony_ci self.indent() 10601cb0ef41Sopenharmony_ci self.writeline('yield ') 10611cb0ef41Sopenharmony_ci self.visit(node.target, loop_frame) 10621cb0ef41Sopenharmony_ci self.outdent(3) 10631cb0ef41Sopenharmony_ci self.leave_frame(test_frame, with_python_scope=True) 10641cb0ef41Sopenharmony_ci 10651cb0ef41Sopenharmony_ci # if we don't have an recursive loop we have to find the shadowed 10661cb0ef41Sopenharmony_ci # variables at that point. Because loops can be nested but the loop 10671cb0ef41Sopenharmony_ci # variable is a special one we have to enforce aliasing for it. 10681cb0ef41Sopenharmony_ci if node.recursive: 10691cb0ef41Sopenharmony_ci self.writeline('%s(reciter, loop_render_func, depth=0):' % 10701cb0ef41Sopenharmony_ci self.func('loop'), node) 10711cb0ef41Sopenharmony_ci self.indent() 10721cb0ef41Sopenharmony_ci self.buffer(loop_frame) 10731cb0ef41Sopenharmony_ci 10741cb0ef41Sopenharmony_ci # Use the same buffer for the else frame 10751cb0ef41Sopenharmony_ci else_frame.buffer = loop_frame.buffer 10761cb0ef41Sopenharmony_ci 10771cb0ef41Sopenharmony_ci # make sure the loop variable is a special one and raise a template 10781cb0ef41Sopenharmony_ci # assertion error if a loop tries to write to loop 10791cb0ef41Sopenharmony_ci if extended_loop: 10801cb0ef41Sopenharmony_ci self.writeline('%s = missing' % loop_ref) 10811cb0ef41Sopenharmony_ci 10821cb0ef41Sopenharmony_ci for name in node.find_all(nodes.Name): 10831cb0ef41Sopenharmony_ci if name.ctx == 'store' and name.name == 'loop': 10841cb0ef41Sopenharmony_ci self.fail('Can\'t assign to special loop variable ' 10851cb0ef41Sopenharmony_ci 'in for-loop target', name.lineno) 10861cb0ef41Sopenharmony_ci 10871cb0ef41Sopenharmony_ci if node.else_: 10881cb0ef41Sopenharmony_ci iteration_indicator = self.temporary_identifier() 10891cb0ef41Sopenharmony_ci self.writeline('%s = 1' % iteration_indicator) 10901cb0ef41Sopenharmony_ci 10911cb0ef41Sopenharmony_ci self.writeline(self.environment.is_async and 'async for ' or 'for ', node) 10921cb0ef41Sopenharmony_ci self.visit(node.target, loop_frame) 10931cb0ef41Sopenharmony_ci if extended_loop: 10941cb0ef41Sopenharmony_ci if self.environment.is_async: 10951cb0ef41Sopenharmony_ci self.write(', %s in await make_async_loop_context(' % loop_ref) 10961cb0ef41Sopenharmony_ci else: 10971cb0ef41Sopenharmony_ci self.write(', %s in LoopContext(' % loop_ref) 10981cb0ef41Sopenharmony_ci else: 10991cb0ef41Sopenharmony_ci self.write(' in ') 11001cb0ef41Sopenharmony_ci 11011cb0ef41Sopenharmony_ci if node.test: 11021cb0ef41Sopenharmony_ci self.write('%s(' % loop_filter_func) 11031cb0ef41Sopenharmony_ci if node.recursive: 11041cb0ef41Sopenharmony_ci self.write('reciter') 11051cb0ef41Sopenharmony_ci else: 11061cb0ef41Sopenharmony_ci if self.environment.is_async and not extended_loop: 11071cb0ef41Sopenharmony_ci self.write('auto_aiter(') 11081cb0ef41Sopenharmony_ci self.visit(node.iter, frame) 11091cb0ef41Sopenharmony_ci if self.environment.is_async and not extended_loop: 11101cb0ef41Sopenharmony_ci self.write(')') 11111cb0ef41Sopenharmony_ci if node.test: 11121cb0ef41Sopenharmony_ci self.write(')') 11131cb0ef41Sopenharmony_ci 11141cb0ef41Sopenharmony_ci if node.recursive: 11151cb0ef41Sopenharmony_ci self.write(', undefined, loop_render_func, depth):') 11161cb0ef41Sopenharmony_ci else: 11171cb0ef41Sopenharmony_ci self.write(extended_loop and ', undefined):' or ':') 11181cb0ef41Sopenharmony_ci 11191cb0ef41Sopenharmony_ci self.indent() 11201cb0ef41Sopenharmony_ci self.enter_frame(loop_frame) 11211cb0ef41Sopenharmony_ci 11221cb0ef41Sopenharmony_ci self.blockvisit(node.body, loop_frame) 11231cb0ef41Sopenharmony_ci if node.else_: 11241cb0ef41Sopenharmony_ci self.writeline('%s = 0' % iteration_indicator) 11251cb0ef41Sopenharmony_ci self.outdent() 11261cb0ef41Sopenharmony_ci self.leave_frame(loop_frame, with_python_scope=node.recursive 11271cb0ef41Sopenharmony_ci and not node.else_) 11281cb0ef41Sopenharmony_ci 11291cb0ef41Sopenharmony_ci if node.else_: 11301cb0ef41Sopenharmony_ci self.writeline('if %s:' % iteration_indicator) 11311cb0ef41Sopenharmony_ci self.indent() 11321cb0ef41Sopenharmony_ci self.enter_frame(else_frame) 11331cb0ef41Sopenharmony_ci self.blockvisit(node.else_, else_frame) 11341cb0ef41Sopenharmony_ci self.leave_frame(else_frame) 11351cb0ef41Sopenharmony_ci self.outdent() 11361cb0ef41Sopenharmony_ci 11371cb0ef41Sopenharmony_ci # if the node was recursive we have to return the buffer contents 11381cb0ef41Sopenharmony_ci # and start the iteration code 11391cb0ef41Sopenharmony_ci if node.recursive: 11401cb0ef41Sopenharmony_ci self.return_buffer_contents(loop_frame) 11411cb0ef41Sopenharmony_ci self.outdent() 11421cb0ef41Sopenharmony_ci self.start_write(frame, node) 11431cb0ef41Sopenharmony_ci if self.environment.is_async: 11441cb0ef41Sopenharmony_ci self.write('await ') 11451cb0ef41Sopenharmony_ci self.write('loop(') 11461cb0ef41Sopenharmony_ci if self.environment.is_async: 11471cb0ef41Sopenharmony_ci self.write('auto_aiter(') 11481cb0ef41Sopenharmony_ci self.visit(node.iter, frame) 11491cb0ef41Sopenharmony_ci if self.environment.is_async: 11501cb0ef41Sopenharmony_ci self.write(')') 11511cb0ef41Sopenharmony_ci self.write(', loop)') 11521cb0ef41Sopenharmony_ci self.end_write(frame) 11531cb0ef41Sopenharmony_ci 11541cb0ef41Sopenharmony_ci def visit_If(self, node, frame): 11551cb0ef41Sopenharmony_ci if_frame = frame.soft() 11561cb0ef41Sopenharmony_ci self.writeline('if ', node) 11571cb0ef41Sopenharmony_ci self.visit(node.test, if_frame) 11581cb0ef41Sopenharmony_ci self.write(':') 11591cb0ef41Sopenharmony_ci self.indent() 11601cb0ef41Sopenharmony_ci self.blockvisit(node.body, if_frame) 11611cb0ef41Sopenharmony_ci self.outdent() 11621cb0ef41Sopenharmony_ci for elif_ in node.elif_: 11631cb0ef41Sopenharmony_ci self.writeline('elif ', elif_) 11641cb0ef41Sopenharmony_ci self.visit(elif_.test, if_frame) 11651cb0ef41Sopenharmony_ci self.write(':') 11661cb0ef41Sopenharmony_ci self.indent() 11671cb0ef41Sopenharmony_ci self.blockvisit(elif_.body, if_frame) 11681cb0ef41Sopenharmony_ci self.outdent() 11691cb0ef41Sopenharmony_ci if node.else_: 11701cb0ef41Sopenharmony_ci self.writeline('else:') 11711cb0ef41Sopenharmony_ci self.indent() 11721cb0ef41Sopenharmony_ci self.blockvisit(node.else_, if_frame) 11731cb0ef41Sopenharmony_ci self.outdent() 11741cb0ef41Sopenharmony_ci 11751cb0ef41Sopenharmony_ci def visit_Macro(self, node, frame): 11761cb0ef41Sopenharmony_ci macro_frame, macro_ref = self.macro_body(node, frame) 11771cb0ef41Sopenharmony_ci self.newline() 11781cb0ef41Sopenharmony_ci if frame.toplevel: 11791cb0ef41Sopenharmony_ci if not node.name.startswith('_'): 11801cb0ef41Sopenharmony_ci self.write('context.exported_vars.add(%r)' % node.name) 11811cb0ef41Sopenharmony_ci ref = frame.symbols.ref(node.name) 11821cb0ef41Sopenharmony_ci self.writeline('context.vars[%r] = ' % node.name) 11831cb0ef41Sopenharmony_ci self.write('%s = ' % frame.symbols.ref(node.name)) 11841cb0ef41Sopenharmony_ci self.macro_def(macro_ref, macro_frame) 11851cb0ef41Sopenharmony_ci 11861cb0ef41Sopenharmony_ci def visit_CallBlock(self, node, frame): 11871cb0ef41Sopenharmony_ci call_frame, macro_ref = self.macro_body(node, frame) 11881cb0ef41Sopenharmony_ci self.writeline('caller = ') 11891cb0ef41Sopenharmony_ci self.macro_def(macro_ref, call_frame) 11901cb0ef41Sopenharmony_ci self.start_write(frame, node) 11911cb0ef41Sopenharmony_ci self.visit_Call(node.call, frame, forward_caller=True) 11921cb0ef41Sopenharmony_ci self.end_write(frame) 11931cb0ef41Sopenharmony_ci 11941cb0ef41Sopenharmony_ci def visit_FilterBlock(self, node, frame): 11951cb0ef41Sopenharmony_ci filter_frame = frame.inner() 11961cb0ef41Sopenharmony_ci filter_frame.symbols.analyze_node(node) 11971cb0ef41Sopenharmony_ci self.enter_frame(filter_frame) 11981cb0ef41Sopenharmony_ci self.buffer(filter_frame) 11991cb0ef41Sopenharmony_ci self.blockvisit(node.body, filter_frame) 12001cb0ef41Sopenharmony_ci self.start_write(frame, node) 12011cb0ef41Sopenharmony_ci self.visit_Filter(node.filter, filter_frame) 12021cb0ef41Sopenharmony_ci self.end_write(frame) 12031cb0ef41Sopenharmony_ci self.leave_frame(filter_frame) 12041cb0ef41Sopenharmony_ci 12051cb0ef41Sopenharmony_ci def visit_With(self, node, frame): 12061cb0ef41Sopenharmony_ci with_frame = frame.inner() 12071cb0ef41Sopenharmony_ci with_frame.symbols.analyze_node(node) 12081cb0ef41Sopenharmony_ci self.enter_frame(with_frame) 12091cb0ef41Sopenharmony_ci for idx, (target, expr) in enumerate(izip(node.targets, node.values)): 12101cb0ef41Sopenharmony_ci self.newline() 12111cb0ef41Sopenharmony_ci self.visit(target, with_frame) 12121cb0ef41Sopenharmony_ci self.write(' = ') 12131cb0ef41Sopenharmony_ci self.visit(expr, frame) 12141cb0ef41Sopenharmony_ci self.blockvisit(node.body, with_frame) 12151cb0ef41Sopenharmony_ci self.leave_frame(with_frame) 12161cb0ef41Sopenharmony_ci 12171cb0ef41Sopenharmony_ci def visit_ExprStmt(self, node, frame): 12181cb0ef41Sopenharmony_ci self.newline(node) 12191cb0ef41Sopenharmony_ci self.visit(node.node, frame) 12201cb0ef41Sopenharmony_ci 12211cb0ef41Sopenharmony_ci def visit_Output(self, node, frame): 12221cb0ef41Sopenharmony_ci # if we have a known extends statement, we don't output anything 12231cb0ef41Sopenharmony_ci # if we are in a require_output_check section 12241cb0ef41Sopenharmony_ci if self.has_known_extends and frame.require_output_check: 12251cb0ef41Sopenharmony_ci return 12261cb0ef41Sopenharmony_ci 12271cb0ef41Sopenharmony_ci allow_constant_finalize = True 12281cb0ef41Sopenharmony_ci if self.environment.finalize: 12291cb0ef41Sopenharmony_ci func = self.environment.finalize 12301cb0ef41Sopenharmony_ci if getattr(func, 'contextfunction', False) or \ 12311cb0ef41Sopenharmony_ci getattr(func, 'evalcontextfunction', False): 12321cb0ef41Sopenharmony_ci allow_constant_finalize = False 12331cb0ef41Sopenharmony_ci elif getattr(func, 'environmentfunction', False): 12341cb0ef41Sopenharmony_ci finalize = lambda x: text_type( 12351cb0ef41Sopenharmony_ci self.environment.finalize(self.environment, x)) 12361cb0ef41Sopenharmony_ci else: 12371cb0ef41Sopenharmony_ci finalize = lambda x: text_type(self.environment.finalize(x)) 12381cb0ef41Sopenharmony_ci else: 12391cb0ef41Sopenharmony_ci finalize = text_type 12401cb0ef41Sopenharmony_ci 12411cb0ef41Sopenharmony_ci # if we are inside a frame that requires output checking, we do so 12421cb0ef41Sopenharmony_ci outdent_later = False 12431cb0ef41Sopenharmony_ci if frame.require_output_check: 12441cb0ef41Sopenharmony_ci self.writeline('if parent_template is None:') 12451cb0ef41Sopenharmony_ci self.indent() 12461cb0ef41Sopenharmony_ci outdent_later = True 12471cb0ef41Sopenharmony_ci 12481cb0ef41Sopenharmony_ci # try to evaluate as many chunks as possible into a static 12491cb0ef41Sopenharmony_ci # string at compile time. 12501cb0ef41Sopenharmony_ci body = [] 12511cb0ef41Sopenharmony_ci for child in node.nodes: 12521cb0ef41Sopenharmony_ci try: 12531cb0ef41Sopenharmony_ci if not allow_constant_finalize: 12541cb0ef41Sopenharmony_ci raise nodes.Impossible() 12551cb0ef41Sopenharmony_ci const = child.as_const(frame.eval_ctx) 12561cb0ef41Sopenharmony_ci except nodes.Impossible: 12571cb0ef41Sopenharmony_ci body.append(child) 12581cb0ef41Sopenharmony_ci continue 12591cb0ef41Sopenharmony_ci # the frame can't be volatile here, becaus otherwise the 12601cb0ef41Sopenharmony_ci # as_const() function would raise an Impossible exception 12611cb0ef41Sopenharmony_ci # at that point. 12621cb0ef41Sopenharmony_ci try: 12631cb0ef41Sopenharmony_ci if frame.eval_ctx.autoescape: 12641cb0ef41Sopenharmony_ci if hasattr(const, '__html__'): 12651cb0ef41Sopenharmony_ci const = const.__html__() 12661cb0ef41Sopenharmony_ci else: 12671cb0ef41Sopenharmony_ci const = escape(const) 12681cb0ef41Sopenharmony_ci const = finalize(const) 12691cb0ef41Sopenharmony_ci except Exception: 12701cb0ef41Sopenharmony_ci # if something goes wrong here we evaluate the node 12711cb0ef41Sopenharmony_ci # at runtime for easier debugging 12721cb0ef41Sopenharmony_ci body.append(child) 12731cb0ef41Sopenharmony_ci continue 12741cb0ef41Sopenharmony_ci if body and isinstance(body[-1], list): 12751cb0ef41Sopenharmony_ci body[-1].append(const) 12761cb0ef41Sopenharmony_ci else: 12771cb0ef41Sopenharmony_ci body.append([const]) 12781cb0ef41Sopenharmony_ci 12791cb0ef41Sopenharmony_ci # if we have less than 3 nodes or a buffer we yield or extend/append 12801cb0ef41Sopenharmony_ci if len(body) < 3 or frame.buffer is not None: 12811cb0ef41Sopenharmony_ci if frame.buffer is not None: 12821cb0ef41Sopenharmony_ci # for one item we append, for more we extend 12831cb0ef41Sopenharmony_ci if len(body) == 1: 12841cb0ef41Sopenharmony_ci self.writeline('%s.append(' % frame.buffer) 12851cb0ef41Sopenharmony_ci else: 12861cb0ef41Sopenharmony_ci self.writeline('%s.extend((' % frame.buffer) 12871cb0ef41Sopenharmony_ci self.indent() 12881cb0ef41Sopenharmony_ci for item in body: 12891cb0ef41Sopenharmony_ci if isinstance(item, list): 12901cb0ef41Sopenharmony_ci val = repr(concat(item)) 12911cb0ef41Sopenharmony_ci if frame.buffer is None: 12921cb0ef41Sopenharmony_ci self.writeline('yield ' + val) 12931cb0ef41Sopenharmony_ci else: 12941cb0ef41Sopenharmony_ci self.writeline(val + ',') 12951cb0ef41Sopenharmony_ci else: 12961cb0ef41Sopenharmony_ci if frame.buffer is None: 12971cb0ef41Sopenharmony_ci self.writeline('yield ', item) 12981cb0ef41Sopenharmony_ci else: 12991cb0ef41Sopenharmony_ci self.newline(item) 13001cb0ef41Sopenharmony_ci close = 1 13011cb0ef41Sopenharmony_ci if frame.eval_ctx.volatile: 13021cb0ef41Sopenharmony_ci self.write('(escape if context.eval_ctx.autoescape' 13031cb0ef41Sopenharmony_ci ' else to_string)(') 13041cb0ef41Sopenharmony_ci elif frame.eval_ctx.autoescape: 13051cb0ef41Sopenharmony_ci self.write('escape(') 13061cb0ef41Sopenharmony_ci else: 13071cb0ef41Sopenharmony_ci self.write('to_string(') 13081cb0ef41Sopenharmony_ci if self.environment.finalize is not None: 13091cb0ef41Sopenharmony_ci self.write('environment.finalize(') 13101cb0ef41Sopenharmony_ci if getattr(self.environment.finalize, 13111cb0ef41Sopenharmony_ci "contextfunction", False): 13121cb0ef41Sopenharmony_ci self.write('context, ') 13131cb0ef41Sopenharmony_ci close += 1 13141cb0ef41Sopenharmony_ci self.visit(item, frame) 13151cb0ef41Sopenharmony_ci self.write(')' * close) 13161cb0ef41Sopenharmony_ci if frame.buffer is not None: 13171cb0ef41Sopenharmony_ci self.write(',') 13181cb0ef41Sopenharmony_ci if frame.buffer is not None: 13191cb0ef41Sopenharmony_ci # close the open parentheses 13201cb0ef41Sopenharmony_ci self.outdent() 13211cb0ef41Sopenharmony_ci self.writeline(len(body) == 1 and ')' or '))') 13221cb0ef41Sopenharmony_ci 13231cb0ef41Sopenharmony_ci # otherwise we create a format string as this is faster in that case 13241cb0ef41Sopenharmony_ci else: 13251cb0ef41Sopenharmony_ci format = [] 13261cb0ef41Sopenharmony_ci arguments = [] 13271cb0ef41Sopenharmony_ci for item in body: 13281cb0ef41Sopenharmony_ci if isinstance(item, list): 13291cb0ef41Sopenharmony_ci format.append(concat(item).replace('%', '%%')) 13301cb0ef41Sopenharmony_ci else: 13311cb0ef41Sopenharmony_ci format.append('%s') 13321cb0ef41Sopenharmony_ci arguments.append(item) 13331cb0ef41Sopenharmony_ci self.writeline('yield ') 13341cb0ef41Sopenharmony_ci self.write(repr(concat(format)) + ' % (') 13351cb0ef41Sopenharmony_ci self.indent() 13361cb0ef41Sopenharmony_ci for argument in arguments: 13371cb0ef41Sopenharmony_ci self.newline(argument) 13381cb0ef41Sopenharmony_ci close = 0 13391cb0ef41Sopenharmony_ci if frame.eval_ctx.volatile: 13401cb0ef41Sopenharmony_ci self.write('(escape if context.eval_ctx.autoescape else' 13411cb0ef41Sopenharmony_ci ' to_string)(') 13421cb0ef41Sopenharmony_ci close += 1 13431cb0ef41Sopenharmony_ci elif frame.eval_ctx.autoescape: 13441cb0ef41Sopenharmony_ci self.write('escape(') 13451cb0ef41Sopenharmony_ci close += 1 13461cb0ef41Sopenharmony_ci if self.environment.finalize is not None: 13471cb0ef41Sopenharmony_ci self.write('environment.finalize(') 13481cb0ef41Sopenharmony_ci if getattr(self.environment.finalize, 13491cb0ef41Sopenharmony_ci 'contextfunction', False): 13501cb0ef41Sopenharmony_ci self.write('context, ') 13511cb0ef41Sopenharmony_ci elif getattr(self.environment.finalize, 13521cb0ef41Sopenharmony_ci 'evalcontextfunction', False): 13531cb0ef41Sopenharmony_ci self.write('context.eval_ctx, ') 13541cb0ef41Sopenharmony_ci elif getattr(self.environment.finalize, 13551cb0ef41Sopenharmony_ci 'environmentfunction', False): 13561cb0ef41Sopenharmony_ci self.write('environment, ') 13571cb0ef41Sopenharmony_ci close += 1 13581cb0ef41Sopenharmony_ci self.visit(argument, frame) 13591cb0ef41Sopenharmony_ci self.write(')' * close + ', ') 13601cb0ef41Sopenharmony_ci self.outdent() 13611cb0ef41Sopenharmony_ci self.writeline(')') 13621cb0ef41Sopenharmony_ci 13631cb0ef41Sopenharmony_ci if outdent_later: 13641cb0ef41Sopenharmony_ci self.outdent() 13651cb0ef41Sopenharmony_ci 13661cb0ef41Sopenharmony_ci def visit_Assign(self, node, frame): 13671cb0ef41Sopenharmony_ci self.push_assign_tracking() 13681cb0ef41Sopenharmony_ci self.newline(node) 13691cb0ef41Sopenharmony_ci self.visit(node.target, frame) 13701cb0ef41Sopenharmony_ci self.write(' = ') 13711cb0ef41Sopenharmony_ci self.visit(node.node, frame) 13721cb0ef41Sopenharmony_ci self.pop_assign_tracking(frame) 13731cb0ef41Sopenharmony_ci 13741cb0ef41Sopenharmony_ci def visit_AssignBlock(self, node, frame): 13751cb0ef41Sopenharmony_ci self.push_assign_tracking() 13761cb0ef41Sopenharmony_ci block_frame = frame.inner() 13771cb0ef41Sopenharmony_ci # This is a special case. Since a set block always captures we 13781cb0ef41Sopenharmony_ci # will disable output checks. This way one can use set blocks 13791cb0ef41Sopenharmony_ci # toplevel even in extended templates. 13801cb0ef41Sopenharmony_ci block_frame.require_output_check = False 13811cb0ef41Sopenharmony_ci block_frame.symbols.analyze_node(node) 13821cb0ef41Sopenharmony_ci self.enter_frame(block_frame) 13831cb0ef41Sopenharmony_ci self.buffer(block_frame) 13841cb0ef41Sopenharmony_ci self.blockvisit(node.body, block_frame) 13851cb0ef41Sopenharmony_ci self.newline(node) 13861cb0ef41Sopenharmony_ci self.visit(node.target, frame) 13871cb0ef41Sopenharmony_ci self.write(' = (Markup if context.eval_ctx.autoescape ' 13881cb0ef41Sopenharmony_ci 'else identity)(') 13891cb0ef41Sopenharmony_ci if node.filter is not None: 13901cb0ef41Sopenharmony_ci self.visit_Filter(node.filter, block_frame) 13911cb0ef41Sopenharmony_ci else: 13921cb0ef41Sopenharmony_ci self.write('concat(%s)' % block_frame.buffer) 13931cb0ef41Sopenharmony_ci self.write(')') 13941cb0ef41Sopenharmony_ci self.pop_assign_tracking(frame) 13951cb0ef41Sopenharmony_ci self.leave_frame(block_frame) 13961cb0ef41Sopenharmony_ci 13971cb0ef41Sopenharmony_ci # -- Expression Visitors 13981cb0ef41Sopenharmony_ci 13991cb0ef41Sopenharmony_ci def visit_Name(self, node, frame): 14001cb0ef41Sopenharmony_ci if node.ctx == 'store' and frame.toplevel: 14011cb0ef41Sopenharmony_ci if self._assign_stack: 14021cb0ef41Sopenharmony_ci self._assign_stack[-1].add(node.name) 14031cb0ef41Sopenharmony_ci ref = frame.symbols.ref(node.name) 14041cb0ef41Sopenharmony_ci 14051cb0ef41Sopenharmony_ci # If we are looking up a variable we might have to deal with the 14061cb0ef41Sopenharmony_ci # case where it's undefined. We can skip that case if the load 14071cb0ef41Sopenharmony_ci # instruction indicates a parameter which are always defined. 14081cb0ef41Sopenharmony_ci if node.ctx == 'load': 14091cb0ef41Sopenharmony_ci load = frame.symbols.find_load(ref) 14101cb0ef41Sopenharmony_ci if not (load is not None and load[0] == VAR_LOAD_PARAMETER and \ 14111cb0ef41Sopenharmony_ci not self.parameter_is_undeclared(ref)): 14121cb0ef41Sopenharmony_ci self.write('(undefined(name=%r) if %s is missing else %s)' % 14131cb0ef41Sopenharmony_ci (node.name, ref, ref)) 14141cb0ef41Sopenharmony_ci return 14151cb0ef41Sopenharmony_ci 14161cb0ef41Sopenharmony_ci self.write(ref) 14171cb0ef41Sopenharmony_ci 14181cb0ef41Sopenharmony_ci def visit_NSRef(self, node, frame): 14191cb0ef41Sopenharmony_ci # NSRefs can only be used to store values; since they use the normal 14201cb0ef41Sopenharmony_ci # `foo.bar` notation they will be parsed as a normal attribute access 14211cb0ef41Sopenharmony_ci # when used anywhere but in a `set` context 14221cb0ef41Sopenharmony_ci ref = frame.symbols.ref(node.name) 14231cb0ef41Sopenharmony_ci self.writeline('if not isinstance(%s, Namespace):' % ref) 14241cb0ef41Sopenharmony_ci self.indent() 14251cb0ef41Sopenharmony_ci self.writeline('raise TemplateRuntimeError(%r)' % 14261cb0ef41Sopenharmony_ci 'cannot assign attribute on non-namespace object') 14271cb0ef41Sopenharmony_ci self.outdent() 14281cb0ef41Sopenharmony_ci self.writeline('%s[%r]' % (ref, node.attr)) 14291cb0ef41Sopenharmony_ci 14301cb0ef41Sopenharmony_ci def visit_Const(self, node, frame): 14311cb0ef41Sopenharmony_ci val = node.as_const(frame.eval_ctx) 14321cb0ef41Sopenharmony_ci if isinstance(val, float): 14331cb0ef41Sopenharmony_ci self.write(str(val)) 14341cb0ef41Sopenharmony_ci else: 14351cb0ef41Sopenharmony_ci self.write(repr(val)) 14361cb0ef41Sopenharmony_ci 14371cb0ef41Sopenharmony_ci def visit_TemplateData(self, node, frame): 14381cb0ef41Sopenharmony_ci try: 14391cb0ef41Sopenharmony_ci self.write(repr(node.as_const(frame.eval_ctx))) 14401cb0ef41Sopenharmony_ci except nodes.Impossible: 14411cb0ef41Sopenharmony_ci self.write('(Markup if context.eval_ctx.autoescape else identity)(%r)' 14421cb0ef41Sopenharmony_ci % node.data) 14431cb0ef41Sopenharmony_ci 14441cb0ef41Sopenharmony_ci def visit_Tuple(self, node, frame): 14451cb0ef41Sopenharmony_ci self.write('(') 14461cb0ef41Sopenharmony_ci idx = -1 14471cb0ef41Sopenharmony_ci for idx, item in enumerate(node.items): 14481cb0ef41Sopenharmony_ci if idx: 14491cb0ef41Sopenharmony_ci self.write(', ') 14501cb0ef41Sopenharmony_ci self.visit(item, frame) 14511cb0ef41Sopenharmony_ci self.write(idx == 0 and ',)' or ')') 14521cb0ef41Sopenharmony_ci 14531cb0ef41Sopenharmony_ci def visit_List(self, node, frame): 14541cb0ef41Sopenharmony_ci self.write('[') 14551cb0ef41Sopenharmony_ci for idx, item in enumerate(node.items): 14561cb0ef41Sopenharmony_ci if idx: 14571cb0ef41Sopenharmony_ci self.write(', ') 14581cb0ef41Sopenharmony_ci self.visit(item, frame) 14591cb0ef41Sopenharmony_ci self.write(']') 14601cb0ef41Sopenharmony_ci 14611cb0ef41Sopenharmony_ci def visit_Dict(self, node, frame): 14621cb0ef41Sopenharmony_ci self.write('{') 14631cb0ef41Sopenharmony_ci for idx, item in enumerate(node.items): 14641cb0ef41Sopenharmony_ci if idx: 14651cb0ef41Sopenharmony_ci self.write(', ') 14661cb0ef41Sopenharmony_ci self.visit(item.key, frame) 14671cb0ef41Sopenharmony_ci self.write(': ') 14681cb0ef41Sopenharmony_ci self.visit(item.value, frame) 14691cb0ef41Sopenharmony_ci self.write('}') 14701cb0ef41Sopenharmony_ci 14711cb0ef41Sopenharmony_ci def binop(operator, interceptable=True): 14721cb0ef41Sopenharmony_ci @optimizeconst 14731cb0ef41Sopenharmony_ci def visitor(self, node, frame): 14741cb0ef41Sopenharmony_ci if self.environment.sandboxed and \ 14751cb0ef41Sopenharmony_ci operator in self.environment.intercepted_binops: 14761cb0ef41Sopenharmony_ci self.write('environment.call_binop(context, %r, ' % operator) 14771cb0ef41Sopenharmony_ci self.visit(node.left, frame) 14781cb0ef41Sopenharmony_ci self.write(', ') 14791cb0ef41Sopenharmony_ci self.visit(node.right, frame) 14801cb0ef41Sopenharmony_ci else: 14811cb0ef41Sopenharmony_ci self.write('(') 14821cb0ef41Sopenharmony_ci self.visit(node.left, frame) 14831cb0ef41Sopenharmony_ci self.write(' %s ' % operator) 14841cb0ef41Sopenharmony_ci self.visit(node.right, frame) 14851cb0ef41Sopenharmony_ci self.write(')') 14861cb0ef41Sopenharmony_ci return visitor 14871cb0ef41Sopenharmony_ci 14881cb0ef41Sopenharmony_ci def uaop(operator, interceptable=True): 14891cb0ef41Sopenharmony_ci @optimizeconst 14901cb0ef41Sopenharmony_ci def visitor(self, node, frame): 14911cb0ef41Sopenharmony_ci if self.environment.sandboxed and \ 14921cb0ef41Sopenharmony_ci operator in self.environment.intercepted_unops: 14931cb0ef41Sopenharmony_ci self.write('environment.call_unop(context, %r, ' % operator) 14941cb0ef41Sopenharmony_ci self.visit(node.node, frame) 14951cb0ef41Sopenharmony_ci else: 14961cb0ef41Sopenharmony_ci self.write('(' + operator) 14971cb0ef41Sopenharmony_ci self.visit(node.node, frame) 14981cb0ef41Sopenharmony_ci self.write(')') 14991cb0ef41Sopenharmony_ci return visitor 15001cb0ef41Sopenharmony_ci 15011cb0ef41Sopenharmony_ci visit_Add = binop('+') 15021cb0ef41Sopenharmony_ci visit_Sub = binop('-') 15031cb0ef41Sopenharmony_ci visit_Mul = binop('*') 15041cb0ef41Sopenharmony_ci visit_Div = binop('/') 15051cb0ef41Sopenharmony_ci visit_FloorDiv = binop('//') 15061cb0ef41Sopenharmony_ci visit_Pow = binop('**') 15071cb0ef41Sopenharmony_ci visit_Mod = binop('%') 15081cb0ef41Sopenharmony_ci visit_And = binop('and', interceptable=False) 15091cb0ef41Sopenharmony_ci visit_Or = binop('or', interceptable=False) 15101cb0ef41Sopenharmony_ci visit_Pos = uaop('+') 15111cb0ef41Sopenharmony_ci visit_Neg = uaop('-') 15121cb0ef41Sopenharmony_ci visit_Not = uaop('not ', interceptable=False) 15131cb0ef41Sopenharmony_ci del binop, uaop 15141cb0ef41Sopenharmony_ci 15151cb0ef41Sopenharmony_ci @optimizeconst 15161cb0ef41Sopenharmony_ci def visit_Concat(self, node, frame): 15171cb0ef41Sopenharmony_ci if frame.eval_ctx.volatile: 15181cb0ef41Sopenharmony_ci func_name = '(context.eval_ctx.volatile and' \ 15191cb0ef41Sopenharmony_ci ' markup_join or unicode_join)' 15201cb0ef41Sopenharmony_ci elif frame.eval_ctx.autoescape: 15211cb0ef41Sopenharmony_ci func_name = 'markup_join' 15221cb0ef41Sopenharmony_ci else: 15231cb0ef41Sopenharmony_ci func_name = 'unicode_join' 15241cb0ef41Sopenharmony_ci self.write('%s((' % func_name) 15251cb0ef41Sopenharmony_ci for arg in node.nodes: 15261cb0ef41Sopenharmony_ci self.visit(arg, frame) 15271cb0ef41Sopenharmony_ci self.write(', ') 15281cb0ef41Sopenharmony_ci self.write('))') 15291cb0ef41Sopenharmony_ci 15301cb0ef41Sopenharmony_ci @optimizeconst 15311cb0ef41Sopenharmony_ci def visit_Compare(self, node, frame): 15321cb0ef41Sopenharmony_ci self.visit(node.expr, frame) 15331cb0ef41Sopenharmony_ci for op in node.ops: 15341cb0ef41Sopenharmony_ci self.visit(op, frame) 15351cb0ef41Sopenharmony_ci 15361cb0ef41Sopenharmony_ci def visit_Operand(self, node, frame): 15371cb0ef41Sopenharmony_ci self.write(' %s ' % operators[node.op]) 15381cb0ef41Sopenharmony_ci self.visit(node.expr, frame) 15391cb0ef41Sopenharmony_ci 15401cb0ef41Sopenharmony_ci @optimizeconst 15411cb0ef41Sopenharmony_ci def visit_Getattr(self, node, frame): 15421cb0ef41Sopenharmony_ci self.write('environment.getattr(') 15431cb0ef41Sopenharmony_ci self.visit(node.node, frame) 15441cb0ef41Sopenharmony_ci self.write(', %r)' % node.attr) 15451cb0ef41Sopenharmony_ci 15461cb0ef41Sopenharmony_ci @optimizeconst 15471cb0ef41Sopenharmony_ci def visit_Getitem(self, node, frame): 15481cb0ef41Sopenharmony_ci # slices bypass the environment getitem method. 15491cb0ef41Sopenharmony_ci if isinstance(node.arg, nodes.Slice): 15501cb0ef41Sopenharmony_ci self.visit(node.node, frame) 15511cb0ef41Sopenharmony_ci self.write('[') 15521cb0ef41Sopenharmony_ci self.visit(node.arg, frame) 15531cb0ef41Sopenharmony_ci self.write(']') 15541cb0ef41Sopenharmony_ci else: 15551cb0ef41Sopenharmony_ci self.write('environment.getitem(') 15561cb0ef41Sopenharmony_ci self.visit(node.node, frame) 15571cb0ef41Sopenharmony_ci self.write(', ') 15581cb0ef41Sopenharmony_ci self.visit(node.arg, frame) 15591cb0ef41Sopenharmony_ci self.write(')') 15601cb0ef41Sopenharmony_ci 15611cb0ef41Sopenharmony_ci def visit_Slice(self, node, frame): 15621cb0ef41Sopenharmony_ci if node.start is not None: 15631cb0ef41Sopenharmony_ci self.visit(node.start, frame) 15641cb0ef41Sopenharmony_ci self.write(':') 15651cb0ef41Sopenharmony_ci if node.stop is not None: 15661cb0ef41Sopenharmony_ci self.visit(node.stop, frame) 15671cb0ef41Sopenharmony_ci if node.step is not None: 15681cb0ef41Sopenharmony_ci self.write(':') 15691cb0ef41Sopenharmony_ci self.visit(node.step, frame) 15701cb0ef41Sopenharmony_ci 15711cb0ef41Sopenharmony_ci @optimizeconst 15721cb0ef41Sopenharmony_ci def visit_Filter(self, node, frame): 15731cb0ef41Sopenharmony_ci if self.environment.is_async: 15741cb0ef41Sopenharmony_ci self.write('await auto_await(') 15751cb0ef41Sopenharmony_ci self.write(self.filters[node.name] + '(') 15761cb0ef41Sopenharmony_ci func = self.environment.filters.get(node.name) 15771cb0ef41Sopenharmony_ci if func is None: 15781cb0ef41Sopenharmony_ci self.fail('no filter named %r' % node.name, node.lineno) 15791cb0ef41Sopenharmony_ci if getattr(func, 'contextfilter', False): 15801cb0ef41Sopenharmony_ci self.write('context, ') 15811cb0ef41Sopenharmony_ci elif getattr(func, 'evalcontextfilter', False): 15821cb0ef41Sopenharmony_ci self.write('context.eval_ctx, ') 15831cb0ef41Sopenharmony_ci elif getattr(func, 'environmentfilter', False): 15841cb0ef41Sopenharmony_ci self.write('environment, ') 15851cb0ef41Sopenharmony_ci 15861cb0ef41Sopenharmony_ci # if the filter node is None we are inside a filter block 15871cb0ef41Sopenharmony_ci # and want to write to the current buffer 15881cb0ef41Sopenharmony_ci if node.node is not None: 15891cb0ef41Sopenharmony_ci self.visit(node.node, frame) 15901cb0ef41Sopenharmony_ci elif frame.eval_ctx.volatile: 15911cb0ef41Sopenharmony_ci self.write('(context.eval_ctx.autoescape and' 15921cb0ef41Sopenharmony_ci ' Markup(concat(%s)) or concat(%s))' % 15931cb0ef41Sopenharmony_ci (frame.buffer, frame.buffer)) 15941cb0ef41Sopenharmony_ci elif frame.eval_ctx.autoescape: 15951cb0ef41Sopenharmony_ci self.write('Markup(concat(%s))' % frame.buffer) 15961cb0ef41Sopenharmony_ci else: 15971cb0ef41Sopenharmony_ci self.write('concat(%s)' % frame.buffer) 15981cb0ef41Sopenharmony_ci self.signature(node, frame) 15991cb0ef41Sopenharmony_ci self.write(')') 16001cb0ef41Sopenharmony_ci if self.environment.is_async: 16011cb0ef41Sopenharmony_ci self.write(')') 16021cb0ef41Sopenharmony_ci 16031cb0ef41Sopenharmony_ci @optimizeconst 16041cb0ef41Sopenharmony_ci def visit_Test(self, node, frame): 16051cb0ef41Sopenharmony_ci self.write(self.tests[node.name] + '(') 16061cb0ef41Sopenharmony_ci if node.name not in self.environment.tests: 16071cb0ef41Sopenharmony_ci self.fail('no test named %r' % node.name, node.lineno) 16081cb0ef41Sopenharmony_ci self.visit(node.node, frame) 16091cb0ef41Sopenharmony_ci self.signature(node, frame) 16101cb0ef41Sopenharmony_ci self.write(')') 16111cb0ef41Sopenharmony_ci 16121cb0ef41Sopenharmony_ci @optimizeconst 16131cb0ef41Sopenharmony_ci def visit_CondExpr(self, node, frame): 16141cb0ef41Sopenharmony_ci def write_expr2(): 16151cb0ef41Sopenharmony_ci if node.expr2 is not None: 16161cb0ef41Sopenharmony_ci return self.visit(node.expr2, frame) 16171cb0ef41Sopenharmony_ci self.write('undefined(%r)' % ('the inline if-' 16181cb0ef41Sopenharmony_ci 'expression on %s evaluated to false and ' 16191cb0ef41Sopenharmony_ci 'no else section was defined.' % self.position(node))) 16201cb0ef41Sopenharmony_ci 16211cb0ef41Sopenharmony_ci self.write('(') 16221cb0ef41Sopenharmony_ci self.visit(node.expr1, frame) 16231cb0ef41Sopenharmony_ci self.write(' if ') 16241cb0ef41Sopenharmony_ci self.visit(node.test, frame) 16251cb0ef41Sopenharmony_ci self.write(' else ') 16261cb0ef41Sopenharmony_ci write_expr2() 16271cb0ef41Sopenharmony_ci self.write(')') 16281cb0ef41Sopenharmony_ci 16291cb0ef41Sopenharmony_ci @optimizeconst 16301cb0ef41Sopenharmony_ci def visit_Call(self, node, frame, forward_caller=False): 16311cb0ef41Sopenharmony_ci if self.environment.is_async: 16321cb0ef41Sopenharmony_ci self.write('await auto_await(') 16331cb0ef41Sopenharmony_ci if self.environment.sandboxed: 16341cb0ef41Sopenharmony_ci self.write('environment.call(context, ') 16351cb0ef41Sopenharmony_ci else: 16361cb0ef41Sopenharmony_ci self.write('context.call(') 16371cb0ef41Sopenharmony_ci self.visit(node.node, frame) 16381cb0ef41Sopenharmony_ci extra_kwargs = forward_caller and {'caller': 'caller'} or None 16391cb0ef41Sopenharmony_ci self.signature(node, frame, extra_kwargs) 16401cb0ef41Sopenharmony_ci self.write(')') 16411cb0ef41Sopenharmony_ci if self.environment.is_async: 16421cb0ef41Sopenharmony_ci self.write(')') 16431cb0ef41Sopenharmony_ci 16441cb0ef41Sopenharmony_ci def visit_Keyword(self, node, frame): 16451cb0ef41Sopenharmony_ci self.write(node.key + '=') 16461cb0ef41Sopenharmony_ci self.visit(node.value, frame) 16471cb0ef41Sopenharmony_ci 16481cb0ef41Sopenharmony_ci # -- Unused nodes for extensions 16491cb0ef41Sopenharmony_ci 16501cb0ef41Sopenharmony_ci def visit_MarkSafe(self, node, frame): 16511cb0ef41Sopenharmony_ci self.write('Markup(') 16521cb0ef41Sopenharmony_ci self.visit(node.expr, frame) 16531cb0ef41Sopenharmony_ci self.write(')') 16541cb0ef41Sopenharmony_ci 16551cb0ef41Sopenharmony_ci def visit_MarkSafeIfAutoescape(self, node, frame): 16561cb0ef41Sopenharmony_ci self.write('(context.eval_ctx.autoescape and Markup or identity)(') 16571cb0ef41Sopenharmony_ci self.visit(node.expr, frame) 16581cb0ef41Sopenharmony_ci self.write(')') 16591cb0ef41Sopenharmony_ci 16601cb0ef41Sopenharmony_ci def visit_EnvironmentAttribute(self, node, frame): 16611cb0ef41Sopenharmony_ci self.write('environment.' + node.name) 16621cb0ef41Sopenharmony_ci 16631cb0ef41Sopenharmony_ci def visit_ExtensionAttribute(self, node, frame): 16641cb0ef41Sopenharmony_ci self.write('environment.extensions[%r].%s' % (node.identifier, node.name)) 16651cb0ef41Sopenharmony_ci 16661cb0ef41Sopenharmony_ci def visit_ImportedName(self, node, frame): 16671cb0ef41Sopenharmony_ci self.write(self.import_aliases[node.importname]) 16681cb0ef41Sopenharmony_ci 16691cb0ef41Sopenharmony_ci def visit_InternalName(self, node, frame): 16701cb0ef41Sopenharmony_ci self.write(node.name) 16711cb0ef41Sopenharmony_ci 16721cb0ef41Sopenharmony_ci def visit_ContextReference(self, node, frame): 16731cb0ef41Sopenharmony_ci self.write('context') 16741cb0ef41Sopenharmony_ci 16751cb0ef41Sopenharmony_ci def visit_Continue(self, node, frame): 16761cb0ef41Sopenharmony_ci self.writeline('continue', node) 16771cb0ef41Sopenharmony_ci 16781cb0ef41Sopenharmony_ci def visit_Break(self, node, frame): 16791cb0ef41Sopenharmony_ci self.writeline('break', node) 16801cb0ef41Sopenharmony_ci 16811cb0ef41Sopenharmony_ci def visit_Scope(self, node, frame): 16821cb0ef41Sopenharmony_ci scope_frame = frame.inner() 16831cb0ef41Sopenharmony_ci scope_frame.symbols.analyze_node(node) 16841cb0ef41Sopenharmony_ci self.enter_frame(scope_frame) 16851cb0ef41Sopenharmony_ci self.blockvisit(node.body, scope_frame) 16861cb0ef41Sopenharmony_ci self.leave_frame(scope_frame) 16871cb0ef41Sopenharmony_ci 16881cb0ef41Sopenharmony_ci def visit_OverlayScope(self, node, frame): 16891cb0ef41Sopenharmony_ci ctx = self.temporary_identifier() 16901cb0ef41Sopenharmony_ci self.writeline('%s = %s' % (ctx, self.derive_context(frame))) 16911cb0ef41Sopenharmony_ci self.writeline('%s.vars = ' % ctx) 16921cb0ef41Sopenharmony_ci self.visit(node.context, frame) 16931cb0ef41Sopenharmony_ci self.push_context_reference(ctx) 16941cb0ef41Sopenharmony_ci 16951cb0ef41Sopenharmony_ci scope_frame = frame.inner(isolated=True) 16961cb0ef41Sopenharmony_ci scope_frame.symbols.analyze_node(node) 16971cb0ef41Sopenharmony_ci self.enter_frame(scope_frame) 16981cb0ef41Sopenharmony_ci self.blockvisit(node.body, scope_frame) 16991cb0ef41Sopenharmony_ci self.leave_frame(scope_frame) 17001cb0ef41Sopenharmony_ci self.pop_context_reference() 17011cb0ef41Sopenharmony_ci 17021cb0ef41Sopenharmony_ci def visit_EvalContextModifier(self, node, frame): 17031cb0ef41Sopenharmony_ci for keyword in node.options: 17041cb0ef41Sopenharmony_ci self.writeline('context.eval_ctx.%s = ' % keyword.key) 17051cb0ef41Sopenharmony_ci self.visit(keyword.value, frame) 17061cb0ef41Sopenharmony_ci try: 17071cb0ef41Sopenharmony_ci val = keyword.value.as_const(frame.eval_ctx) 17081cb0ef41Sopenharmony_ci except nodes.Impossible: 17091cb0ef41Sopenharmony_ci frame.eval_ctx.volatile = True 17101cb0ef41Sopenharmony_ci else: 17111cb0ef41Sopenharmony_ci setattr(frame.eval_ctx, keyword.key, val) 17121cb0ef41Sopenharmony_ci 17131cb0ef41Sopenharmony_ci def visit_ScopedEvalContextModifier(self, node, frame): 17141cb0ef41Sopenharmony_ci old_ctx_name = self.temporary_identifier() 17151cb0ef41Sopenharmony_ci saved_ctx = frame.eval_ctx.save() 17161cb0ef41Sopenharmony_ci self.writeline('%s = context.eval_ctx.save()' % old_ctx_name) 17171cb0ef41Sopenharmony_ci self.visit_EvalContextModifier(node, frame) 17181cb0ef41Sopenharmony_ci for child in node.body: 17191cb0ef41Sopenharmony_ci self.visit(child, frame) 17201cb0ef41Sopenharmony_ci frame.eval_ctx.revert(saved_ctx) 17211cb0ef41Sopenharmony_ci self.writeline('context.eval_ctx.revert(%s)' % old_ctx_name) 1722