1*635a8641SAndroid Build Coastguard Worker# -*- coding: utf-8 -*- 2*635a8641SAndroid Build Coastguard Worker""" 3*635a8641SAndroid Build Coastguard Worker jinja2.compiler 4*635a8641SAndroid Build Coastguard Worker ~~~~~~~~~~~~~~~ 5*635a8641SAndroid Build Coastguard Worker 6*635a8641SAndroid Build Coastguard Worker Compiles nodes into python code. 7*635a8641SAndroid Build Coastguard Worker 8*635a8641SAndroid Build Coastguard Worker :copyright: (c) 2017 by the Jinja Team. 9*635a8641SAndroid Build Coastguard Worker :license: BSD, see LICENSE for more details. 10*635a8641SAndroid Build Coastguard Worker""" 11*635a8641SAndroid Build Coastguard Workerfrom itertools import chain 12*635a8641SAndroid Build Coastguard Workerfrom copy import deepcopy 13*635a8641SAndroid Build Coastguard Workerfrom keyword import iskeyword as is_python_keyword 14*635a8641SAndroid Build Coastguard Workerfrom functools import update_wrapper 15*635a8641SAndroid Build Coastguard Workerfrom jinja2 import nodes 16*635a8641SAndroid Build Coastguard Workerfrom jinja2.nodes import EvalContext 17*635a8641SAndroid Build Coastguard Workerfrom jinja2.visitor import NodeVisitor 18*635a8641SAndroid Build Coastguard Workerfrom jinja2.optimizer import Optimizer 19*635a8641SAndroid Build Coastguard Workerfrom jinja2.exceptions import TemplateAssertionError 20*635a8641SAndroid Build Coastguard Workerfrom jinja2.utils import Markup, concat, escape 21*635a8641SAndroid Build Coastguard Workerfrom jinja2._compat import range_type, text_type, string_types, \ 22*635a8641SAndroid Build Coastguard Worker iteritems, NativeStringIO, imap, izip 23*635a8641SAndroid Build Coastguard Workerfrom jinja2.idtracking import Symbols, VAR_LOAD_PARAMETER, \ 24*635a8641SAndroid Build Coastguard Worker VAR_LOAD_RESOLVE, VAR_LOAD_ALIAS, VAR_LOAD_UNDEFINED 25*635a8641SAndroid Build Coastguard Worker 26*635a8641SAndroid Build Coastguard Worker 27*635a8641SAndroid Build Coastguard Workeroperators = { 28*635a8641SAndroid Build Coastguard Worker 'eq': '==', 29*635a8641SAndroid Build Coastguard Worker 'ne': '!=', 30*635a8641SAndroid Build Coastguard Worker 'gt': '>', 31*635a8641SAndroid Build Coastguard Worker 'gteq': '>=', 32*635a8641SAndroid Build Coastguard Worker 'lt': '<', 33*635a8641SAndroid Build Coastguard Worker 'lteq': '<=', 34*635a8641SAndroid Build Coastguard Worker 'in': 'in', 35*635a8641SAndroid Build Coastguard Worker 'notin': 'not in' 36*635a8641SAndroid Build Coastguard Worker} 37*635a8641SAndroid Build Coastguard Worker 38*635a8641SAndroid Build Coastguard Worker# what method to iterate over items do we want to use for dict iteration 39*635a8641SAndroid Build Coastguard Worker# in generated code? on 2.x let's go with iteritems, on 3.x with items 40*635a8641SAndroid Build Coastguard Workerif hasattr(dict, 'iteritems'): 41*635a8641SAndroid Build Coastguard Worker dict_item_iter = 'iteritems' 42*635a8641SAndroid Build Coastguard Workerelse: 43*635a8641SAndroid Build Coastguard Worker dict_item_iter = 'items' 44*635a8641SAndroid Build Coastguard Worker 45*635a8641SAndroid Build Coastguard Workercode_features = ['division'] 46*635a8641SAndroid Build Coastguard Worker 47*635a8641SAndroid Build Coastguard Worker# does this python version support generator stops? (PEP 0479) 48*635a8641SAndroid Build Coastguard Workertry: 49*635a8641SAndroid Build Coastguard Worker exec('from __future__ import generator_stop') 50*635a8641SAndroid Build Coastguard Worker code_features.append('generator_stop') 51*635a8641SAndroid Build Coastguard Workerexcept SyntaxError: 52*635a8641SAndroid Build Coastguard Worker pass 53*635a8641SAndroid Build Coastguard Worker 54*635a8641SAndroid Build Coastguard Worker# does this python version support yield from? 55*635a8641SAndroid Build Coastguard Workertry: 56*635a8641SAndroid Build Coastguard Worker exec('def f(): yield from x()') 57*635a8641SAndroid Build Coastguard Workerexcept SyntaxError: 58*635a8641SAndroid Build Coastguard Worker supports_yield_from = False 59*635a8641SAndroid Build Coastguard Workerelse: 60*635a8641SAndroid Build Coastguard Worker supports_yield_from = True 61*635a8641SAndroid Build Coastguard Worker 62*635a8641SAndroid Build Coastguard Worker 63*635a8641SAndroid Build Coastguard Workerdef optimizeconst(f): 64*635a8641SAndroid Build Coastguard Worker def new_func(self, node, frame, **kwargs): 65*635a8641SAndroid Build Coastguard Worker # Only optimize if the frame is not volatile 66*635a8641SAndroid Build Coastguard Worker if self.optimized and not frame.eval_ctx.volatile: 67*635a8641SAndroid Build Coastguard Worker new_node = self.optimizer.visit(node, frame.eval_ctx) 68*635a8641SAndroid Build Coastguard Worker if new_node != node: 69*635a8641SAndroid Build Coastguard Worker return self.visit(new_node, frame) 70*635a8641SAndroid Build Coastguard Worker return f(self, node, frame, **kwargs) 71*635a8641SAndroid Build Coastguard Worker return update_wrapper(new_func, f) 72*635a8641SAndroid Build Coastguard Worker 73*635a8641SAndroid Build Coastguard Worker 74*635a8641SAndroid Build Coastguard Workerdef generate(node, environment, name, filename, stream=None, 75*635a8641SAndroid Build Coastguard Worker defer_init=False, optimized=True): 76*635a8641SAndroid Build Coastguard Worker """Generate the python source for a node tree.""" 77*635a8641SAndroid Build Coastguard Worker if not isinstance(node, nodes.Template): 78*635a8641SAndroid Build Coastguard Worker raise TypeError('Can\'t compile non template nodes') 79*635a8641SAndroid Build Coastguard Worker generator = environment.code_generator_class(environment, name, filename, 80*635a8641SAndroid Build Coastguard Worker stream, defer_init, 81*635a8641SAndroid Build Coastguard Worker optimized) 82*635a8641SAndroid Build Coastguard Worker generator.visit(node) 83*635a8641SAndroid Build Coastguard Worker if stream is None: 84*635a8641SAndroid Build Coastguard Worker return generator.stream.getvalue() 85*635a8641SAndroid Build Coastguard Worker 86*635a8641SAndroid Build Coastguard Worker 87*635a8641SAndroid Build Coastguard Workerdef has_safe_repr(value): 88*635a8641SAndroid Build Coastguard Worker """Does the node have a safe representation?""" 89*635a8641SAndroid Build Coastguard Worker if value is None or value is NotImplemented or value is Ellipsis: 90*635a8641SAndroid Build Coastguard Worker return True 91*635a8641SAndroid Build Coastguard Worker if type(value) in (bool, int, float, complex, range_type, Markup) + string_types: 92*635a8641SAndroid Build Coastguard Worker return True 93*635a8641SAndroid Build Coastguard Worker if type(value) in (tuple, list, set, frozenset): 94*635a8641SAndroid Build Coastguard Worker for item in value: 95*635a8641SAndroid Build Coastguard Worker if not has_safe_repr(item): 96*635a8641SAndroid Build Coastguard Worker return False 97*635a8641SAndroid Build Coastguard Worker return True 98*635a8641SAndroid Build Coastguard Worker elif type(value) is dict: 99*635a8641SAndroid Build Coastguard Worker for key, value in iteritems(value): 100*635a8641SAndroid Build Coastguard Worker if not has_safe_repr(key): 101*635a8641SAndroid Build Coastguard Worker return False 102*635a8641SAndroid Build Coastguard Worker if not has_safe_repr(value): 103*635a8641SAndroid Build Coastguard Worker return False 104*635a8641SAndroid Build Coastguard Worker return True 105*635a8641SAndroid Build Coastguard Worker return False 106*635a8641SAndroid Build Coastguard Worker 107*635a8641SAndroid Build Coastguard Worker 108*635a8641SAndroid Build Coastguard Workerdef find_undeclared(nodes, names): 109*635a8641SAndroid Build Coastguard Worker """Check if the names passed are accessed undeclared. The return value 110*635a8641SAndroid Build Coastguard Worker is a set of all the undeclared names from the sequence of names found. 111*635a8641SAndroid Build Coastguard Worker """ 112*635a8641SAndroid Build Coastguard Worker visitor = UndeclaredNameVisitor(names) 113*635a8641SAndroid Build Coastguard Worker try: 114*635a8641SAndroid Build Coastguard Worker for node in nodes: 115*635a8641SAndroid Build Coastguard Worker visitor.visit(node) 116*635a8641SAndroid Build Coastguard Worker except VisitorExit: 117*635a8641SAndroid Build Coastguard Worker pass 118*635a8641SAndroid Build Coastguard Worker return visitor.undeclared 119*635a8641SAndroid Build Coastguard Worker 120*635a8641SAndroid Build Coastguard Worker 121*635a8641SAndroid Build Coastguard Workerclass MacroRef(object): 122*635a8641SAndroid Build Coastguard Worker 123*635a8641SAndroid Build Coastguard Worker def __init__(self, node): 124*635a8641SAndroid Build Coastguard Worker self.node = node 125*635a8641SAndroid Build Coastguard Worker self.accesses_caller = False 126*635a8641SAndroid Build Coastguard Worker self.accesses_kwargs = False 127*635a8641SAndroid Build Coastguard Worker self.accesses_varargs = False 128*635a8641SAndroid Build Coastguard Worker 129*635a8641SAndroid Build Coastguard Worker 130*635a8641SAndroid Build Coastguard Workerclass Frame(object): 131*635a8641SAndroid Build Coastguard Worker """Holds compile time information for us.""" 132*635a8641SAndroid Build Coastguard Worker 133*635a8641SAndroid Build Coastguard Worker def __init__(self, eval_ctx, parent=None, level=None): 134*635a8641SAndroid Build Coastguard Worker self.eval_ctx = eval_ctx 135*635a8641SAndroid Build Coastguard Worker self.symbols = Symbols(parent and parent.symbols or None, 136*635a8641SAndroid Build Coastguard Worker level=level) 137*635a8641SAndroid Build Coastguard Worker 138*635a8641SAndroid Build Coastguard Worker # a toplevel frame is the root + soft frames such as if conditions. 139*635a8641SAndroid Build Coastguard Worker self.toplevel = False 140*635a8641SAndroid Build Coastguard Worker 141*635a8641SAndroid Build Coastguard Worker # the root frame is basically just the outermost frame, so no if 142*635a8641SAndroid Build Coastguard Worker # conditions. This information is used to optimize inheritance 143*635a8641SAndroid Build Coastguard Worker # situations. 144*635a8641SAndroid Build Coastguard Worker self.rootlevel = False 145*635a8641SAndroid Build Coastguard Worker 146*635a8641SAndroid Build Coastguard Worker # in some dynamic inheritance situations the compiler needs to add 147*635a8641SAndroid Build Coastguard Worker # write tests around output statements. 148*635a8641SAndroid Build Coastguard Worker self.require_output_check = parent and parent.require_output_check 149*635a8641SAndroid Build Coastguard Worker 150*635a8641SAndroid Build Coastguard Worker # inside some tags we are using a buffer rather than yield statements. 151*635a8641SAndroid Build Coastguard Worker # this for example affects {% filter %} or {% macro %}. If a frame 152*635a8641SAndroid Build Coastguard Worker # is buffered this variable points to the name of the list used as 153*635a8641SAndroid Build Coastguard Worker # buffer. 154*635a8641SAndroid Build Coastguard Worker self.buffer = None 155*635a8641SAndroid Build Coastguard Worker 156*635a8641SAndroid Build Coastguard Worker # the name of the block we're in, otherwise None. 157*635a8641SAndroid Build Coastguard Worker self.block = parent and parent.block or None 158*635a8641SAndroid Build Coastguard Worker 159*635a8641SAndroid Build Coastguard Worker # the parent of this frame 160*635a8641SAndroid Build Coastguard Worker self.parent = parent 161*635a8641SAndroid Build Coastguard Worker 162*635a8641SAndroid Build Coastguard Worker if parent is not None: 163*635a8641SAndroid Build Coastguard Worker self.buffer = parent.buffer 164*635a8641SAndroid Build Coastguard Worker 165*635a8641SAndroid Build Coastguard Worker def copy(self): 166*635a8641SAndroid Build Coastguard Worker """Create a copy of the current one.""" 167*635a8641SAndroid Build Coastguard Worker rv = object.__new__(self.__class__) 168*635a8641SAndroid Build Coastguard Worker rv.__dict__.update(self.__dict__) 169*635a8641SAndroid Build Coastguard Worker rv.symbols = self.symbols.copy() 170*635a8641SAndroid Build Coastguard Worker return rv 171*635a8641SAndroid Build Coastguard Worker 172*635a8641SAndroid Build Coastguard Worker def inner(self, isolated=False): 173*635a8641SAndroid Build Coastguard Worker """Return an inner frame.""" 174*635a8641SAndroid Build Coastguard Worker if isolated: 175*635a8641SAndroid Build Coastguard Worker return Frame(self.eval_ctx, level=self.symbols.level + 1) 176*635a8641SAndroid Build Coastguard Worker return Frame(self.eval_ctx, self) 177*635a8641SAndroid Build Coastguard Worker 178*635a8641SAndroid Build Coastguard Worker def soft(self): 179*635a8641SAndroid Build Coastguard Worker """Return a soft frame. A soft frame may not be modified as 180*635a8641SAndroid Build Coastguard Worker standalone thing as it shares the resources with the frame it 181*635a8641SAndroid Build Coastguard Worker was created of, but it's not a rootlevel frame any longer. 182*635a8641SAndroid Build Coastguard Worker 183*635a8641SAndroid Build Coastguard Worker This is only used to implement if-statements. 184*635a8641SAndroid Build Coastguard Worker """ 185*635a8641SAndroid Build Coastguard Worker rv = self.copy() 186*635a8641SAndroid Build Coastguard Worker rv.rootlevel = False 187*635a8641SAndroid Build Coastguard Worker return rv 188*635a8641SAndroid Build Coastguard Worker 189*635a8641SAndroid Build Coastguard Worker __copy__ = copy 190*635a8641SAndroid Build Coastguard Worker 191*635a8641SAndroid Build Coastguard Worker 192*635a8641SAndroid Build Coastguard Workerclass VisitorExit(RuntimeError): 193*635a8641SAndroid Build Coastguard Worker """Exception used by the `UndeclaredNameVisitor` to signal a stop.""" 194*635a8641SAndroid Build Coastguard Worker 195*635a8641SAndroid Build Coastguard Worker 196*635a8641SAndroid Build Coastguard Workerclass DependencyFinderVisitor(NodeVisitor): 197*635a8641SAndroid Build Coastguard Worker """A visitor that collects filter and test calls.""" 198*635a8641SAndroid Build Coastguard Worker 199*635a8641SAndroid Build Coastguard Worker def __init__(self): 200*635a8641SAndroid Build Coastguard Worker self.filters = set() 201*635a8641SAndroid Build Coastguard Worker self.tests = set() 202*635a8641SAndroid Build Coastguard Worker 203*635a8641SAndroid Build Coastguard Worker def visit_Filter(self, node): 204*635a8641SAndroid Build Coastguard Worker self.generic_visit(node) 205*635a8641SAndroid Build Coastguard Worker self.filters.add(node.name) 206*635a8641SAndroid Build Coastguard Worker 207*635a8641SAndroid Build Coastguard Worker def visit_Test(self, node): 208*635a8641SAndroid Build Coastguard Worker self.generic_visit(node) 209*635a8641SAndroid Build Coastguard Worker self.tests.add(node.name) 210*635a8641SAndroid Build Coastguard Worker 211*635a8641SAndroid Build Coastguard Worker def visit_Block(self, node): 212*635a8641SAndroid Build Coastguard Worker """Stop visiting at blocks.""" 213*635a8641SAndroid Build Coastguard Worker 214*635a8641SAndroid Build Coastguard Worker 215*635a8641SAndroid Build Coastguard Workerclass UndeclaredNameVisitor(NodeVisitor): 216*635a8641SAndroid Build Coastguard Worker """A visitor that checks if a name is accessed without being 217*635a8641SAndroid Build Coastguard Worker declared. This is different from the frame visitor as it will 218*635a8641SAndroid Build Coastguard Worker not stop at closure frames. 219*635a8641SAndroid Build Coastguard Worker """ 220*635a8641SAndroid Build Coastguard Worker 221*635a8641SAndroid Build Coastguard Worker def __init__(self, names): 222*635a8641SAndroid Build Coastguard Worker self.names = set(names) 223*635a8641SAndroid Build Coastguard Worker self.undeclared = set() 224*635a8641SAndroid Build Coastguard Worker 225*635a8641SAndroid Build Coastguard Worker def visit_Name(self, node): 226*635a8641SAndroid Build Coastguard Worker if node.ctx == 'load' and node.name in self.names: 227*635a8641SAndroid Build Coastguard Worker self.undeclared.add(node.name) 228*635a8641SAndroid Build Coastguard Worker if self.undeclared == self.names: 229*635a8641SAndroid Build Coastguard Worker raise VisitorExit() 230*635a8641SAndroid Build Coastguard Worker else: 231*635a8641SAndroid Build Coastguard Worker self.names.discard(node.name) 232*635a8641SAndroid Build Coastguard Worker 233*635a8641SAndroid Build Coastguard Worker def visit_Block(self, node): 234*635a8641SAndroid Build Coastguard Worker """Stop visiting a blocks.""" 235*635a8641SAndroid Build Coastguard Worker 236*635a8641SAndroid Build Coastguard Worker 237*635a8641SAndroid Build Coastguard Workerclass CompilerExit(Exception): 238*635a8641SAndroid Build Coastguard Worker """Raised if the compiler encountered a situation where it just 239*635a8641SAndroid Build Coastguard Worker doesn't make sense to further process the code. Any block that 240*635a8641SAndroid Build Coastguard Worker raises such an exception is not further processed. 241*635a8641SAndroid Build Coastguard Worker """ 242*635a8641SAndroid Build Coastguard Worker 243*635a8641SAndroid Build Coastguard Worker 244*635a8641SAndroid Build Coastguard Workerclass CodeGenerator(NodeVisitor): 245*635a8641SAndroid Build Coastguard Worker 246*635a8641SAndroid Build Coastguard Worker def __init__(self, environment, name, filename, stream=None, 247*635a8641SAndroid Build Coastguard Worker defer_init=False, optimized=True): 248*635a8641SAndroid Build Coastguard Worker if stream is None: 249*635a8641SAndroid Build Coastguard Worker stream = NativeStringIO() 250*635a8641SAndroid Build Coastguard Worker self.environment = environment 251*635a8641SAndroid Build Coastguard Worker self.name = name 252*635a8641SAndroid Build Coastguard Worker self.filename = filename 253*635a8641SAndroid Build Coastguard Worker self.stream = stream 254*635a8641SAndroid Build Coastguard Worker self.created_block_context = False 255*635a8641SAndroid Build Coastguard Worker self.defer_init = defer_init 256*635a8641SAndroid Build Coastguard Worker self.optimized = optimized 257*635a8641SAndroid Build Coastguard Worker if optimized: 258*635a8641SAndroid Build Coastguard Worker self.optimizer = Optimizer(environment) 259*635a8641SAndroid Build Coastguard Worker 260*635a8641SAndroid Build Coastguard Worker # aliases for imports 261*635a8641SAndroid Build Coastguard Worker self.import_aliases = {} 262*635a8641SAndroid Build Coastguard Worker 263*635a8641SAndroid Build Coastguard Worker # a registry for all blocks. Because blocks are moved out 264*635a8641SAndroid Build Coastguard Worker # into the global python scope they are registered here 265*635a8641SAndroid Build Coastguard Worker self.blocks = {} 266*635a8641SAndroid Build Coastguard Worker 267*635a8641SAndroid Build Coastguard Worker # the number of extends statements so far 268*635a8641SAndroid Build Coastguard Worker self.extends_so_far = 0 269*635a8641SAndroid Build Coastguard Worker 270*635a8641SAndroid Build Coastguard Worker # some templates have a rootlevel extends. In this case we 271*635a8641SAndroid Build Coastguard Worker # can safely assume that we're a child template and do some 272*635a8641SAndroid Build Coastguard Worker # more optimizations. 273*635a8641SAndroid Build Coastguard Worker self.has_known_extends = False 274*635a8641SAndroid Build Coastguard Worker 275*635a8641SAndroid Build Coastguard Worker # the current line number 276*635a8641SAndroid Build Coastguard Worker self.code_lineno = 1 277*635a8641SAndroid Build Coastguard Worker 278*635a8641SAndroid Build Coastguard Worker # registry of all filters and tests (global, not block local) 279*635a8641SAndroid Build Coastguard Worker self.tests = {} 280*635a8641SAndroid Build Coastguard Worker self.filters = {} 281*635a8641SAndroid Build Coastguard Worker 282*635a8641SAndroid Build Coastguard Worker # the debug information 283*635a8641SAndroid Build Coastguard Worker self.debug_info = [] 284*635a8641SAndroid Build Coastguard Worker self._write_debug_info = None 285*635a8641SAndroid Build Coastguard Worker 286*635a8641SAndroid Build Coastguard Worker # the number of new lines before the next write() 287*635a8641SAndroid Build Coastguard Worker self._new_lines = 0 288*635a8641SAndroid Build Coastguard Worker 289*635a8641SAndroid Build Coastguard Worker # the line number of the last written statement 290*635a8641SAndroid Build Coastguard Worker self._last_line = 0 291*635a8641SAndroid Build Coastguard Worker 292*635a8641SAndroid Build Coastguard Worker # true if nothing was written so far. 293*635a8641SAndroid Build Coastguard Worker self._first_write = True 294*635a8641SAndroid Build Coastguard Worker 295*635a8641SAndroid Build Coastguard Worker # used by the `temporary_identifier` method to get new 296*635a8641SAndroid Build Coastguard Worker # unique, temporary identifier 297*635a8641SAndroid Build Coastguard Worker self._last_identifier = 0 298*635a8641SAndroid Build Coastguard Worker 299*635a8641SAndroid Build Coastguard Worker # the current indentation 300*635a8641SAndroid Build Coastguard Worker self._indentation = 0 301*635a8641SAndroid Build Coastguard Worker 302*635a8641SAndroid Build Coastguard Worker # Tracks toplevel assignments 303*635a8641SAndroid Build Coastguard Worker self._assign_stack = [] 304*635a8641SAndroid Build Coastguard Worker 305*635a8641SAndroid Build Coastguard Worker # Tracks parameter definition blocks 306*635a8641SAndroid Build Coastguard Worker self._param_def_block = [] 307*635a8641SAndroid Build Coastguard Worker 308*635a8641SAndroid Build Coastguard Worker # Tracks the current context. 309*635a8641SAndroid Build Coastguard Worker self._context_reference_stack = ['context'] 310*635a8641SAndroid Build Coastguard Worker 311*635a8641SAndroid Build Coastguard Worker # -- Various compilation helpers 312*635a8641SAndroid Build Coastguard Worker 313*635a8641SAndroid Build Coastguard Worker def fail(self, msg, lineno): 314*635a8641SAndroid Build Coastguard Worker """Fail with a :exc:`TemplateAssertionError`.""" 315*635a8641SAndroid Build Coastguard Worker raise TemplateAssertionError(msg, lineno, self.name, self.filename) 316*635a8641SAndroid Build Coastguard Worker 317*635a8641SAndroid Build Coastguard Worker def temporary_identifier(self): 318*635a8641SAndroid Build Coastguard Worker """Get a new unique identifier.""" 319*635a8641SAndroid Build Coastguard Worker self._last_identifier += 1 320*635a8641SAndroid Build Coastguard Worker return 't_%d' % self._last_identifier 321*635a8641SAndroid Build Coastguard Worker 322*635a8641SAndroid Build Coastguard Worker def buffer(self, frame): 323*635a8641SAndroid Build Coastguard Worker """Enable buffering for the frame from that point onwards.""" 324*635a8641SAndroid Build Coastguard Worker frame.buffer = self.temporary_identifier() 325*635a8641SAndroid Build Coastguard Worker self.writeline('%s = []' % frame.buffer) 326*635a8641SAndroid Build Coastguard Worker 327*635a8641SAndroid Build Coastguard Worker def return_buffer_contents(self, frame, force_unescaped=False): 328*635a8641SAndroid Build Coastguard Worker """Return the buffer contents of the frame.""" 329*635a8641SAndroid Build Coastguard Worker if not force_unescaped: 330*635a8641SAndroid Build Coastguard Worker if frame.eval_ctx.volatile: 331*635a8641SAndroid Build Coastguard Worker self.writeline('if context.eval_ctx.autoescape:') 332*635a8641SAndroid Build Coastguard Worker self.indent() 333*635a8641SAndroid Build Coastguard Worker self.writeline('return Markup(concat(%s))' % frame.buffer) 334*635a8641SAndroid Build Coastguard Worker self.outdent() 335*635a8641SAndroid Build Coastguard Worker self.writeline('else:') 336*635a8641SAndroid Build Coastguard Worker self.indent() 337*635a8641SAndroid Build Coastguard Worker self.writeline('return concat(%s)' % frame.buffer) 338*635a8641SAndroid Build Coastguard Worker self.outdent() 339*635a8641SAndroid Build Coastguard Worker return 340*635a8641SAndroid Build Coastguard Worker elif frame.eval_ctx.autoescape: 341*635a8641SAndroid Build Coastguard Worker self.writeline('return Markup(concat(%s))' % frame.buffer) 342*635a8641SAndroid Build Coastguard Worker return 343*635a8641SAndroid Build Coastguard Worker self.writeline('return concat(%s)' % frame.buffer) 344*635a8641SAndroid Build Coastguard Worker 345*635a8641SAndroid Build Coastguard Worker def indent(self): 346*635a8641SAndroid Build Coastguard Worker """Indent by one.""" 347*635a8641SAndroid Build Coastguard Worker self._indentation += 1 348*635a8641SAndroid Build Coastguard Worker 349*635a8641SAndroid Build Coastguard Worker def outdent(self, step=1): 350*635a8641SAndroid Build Coastguard Worker """Outdent by step.""" 351*635a8641SAndroid Build Coastguard Worker self._indentation -= step 352*635a8641SAndroid Build Coastguard Worker 353*635a8641SAndroid Build Coastguard Worker def start_write(self, frame, node=None): 354*635a8641SAndroid Build Coastguard Worker """Yield or write into the frame buffer.""" 355*635a8641SAndroid Build Coastguard Worker if frame.buffer is None: 356*635a8641SAndroid Build Coastguard Worker self.writeline('yield ', node) 357*635a8641SAndroid Build Coastguard Worker else: 358*635a8641SAndroid Build Coastguard Worker self.writeline('%s.append(' % frame.buffer, node) 359*635a8641SAndroid Build Coastguard Worker 360*635a8641SAndroid Build Coastguard Worker def end_write(self, frame): 361*635a8641SAndroid Build Coastguard Worker """End the writing process started by `start_write`.""" 362*635a8641SAndroid Build Coastguard Worker if frame.buffer is not None: 363*635a8641SAndroid Build Coastguard Worker self.write(')') 364*635a8641SAndroid Build Coastguard Worker 365*635a8641SAndroid Build Coastguard Worker def simple_write(self, s, frame, node=None): 366*635a8641SAndroid Build Coastguard Worker """Simple shortcut for start_write + write + end_write.""" 367*635a8641SAndroid Build Coastguard Worker self.start_write(frame, node) 368*635a8641SAndroid Build Coastguard Worker self.write(s) 369*635a8641SAndroid Build Coastguard Worker self.end_write(frame) 370*635a8641SAndroid Build Coastguard Worker 371*635a8641SAndroid Build Coastguard Worker def blockvisit(self, nodes, frame): 372*635a8641SAndroid Build Coastguard Worker """Visit a list of nodes as block in a frame. If the current frame 373*635a8641SAndroid Build Coastguard Worker is no buffer a dummy ``if 0: yield None`` is written automatically. 374*635a8641SAndroid Build Coastguard Worker """ 375*635a8641SAndroid Build Coastguard Worker try: 376*635a8641SAndroid Build Coastguard Worker self.writeline('pass') 377*635a8641SAndroid Build Coastguard Worker for node in nodes: 378*635a8641SAndroid Build Coastguard Worker self.visit(node, frame) 379*635a8641SAndroid Build Coastguard Worker except CompilerExit: 380*635a8641SAndroid Build Coastguard Worker pass 381*635a8641SAndroid Build Coastguard Worker 382*635a8641SAndroid Build Coastguard Worker def write(self, x): 383*635a8641SAndroid Build Coastguard Worker """Write a string into the output stream.""" 384*635a8641SAndroid Build Coastguard Worker if self._new_lines: 385*635a8641SAndroid Build Coastguard Worker if not self._first_write: 386*635a8641SAndroid Build Coastguard Worker self.stream.write('\n' * self._new_lines) 387*635a8641SAndroid Build Coastguard Worker self.code_lineno += self._new_lines 388*635a8641SAndroid Build Coastguard Worker if self._write_debug_info is not None: 389*635a8641SAndroid Build Coastguard Worker self.debug_info.append((self._write_debug_info, 390*635a8641SAndroid Build Coastguard Worker self.code_lineno)) 391*635a8641SAndroid Build Coastguard Worker self._write_debug_info = None 392*635a8641SAndroid Build Coastguard Worker self._first_write = False 393*635a8641SAndroid Build Coastguard Worker self.stream.write(' ' * self._indentation) 394*635a8641SAndroid Build Coastguard Worker self._new_lines = 0 395*635a8641SAndroid Build Coastguard Worker self.stream.write(x) 396*635a8641SAndroid Build Coastguard Worker 397*635a8641SAndroid Build Coastguard Worker def writeline(self, x, node=None, extra=0): 398*635a8641SAndroid Build Coastguard Worker """Combination of newline and write.""" 399*635a8641SAndroid Build Coastguard Worker self.newline(node, extra) 400*635a8641SAndroid Build Coastguard Worker self.write(x) 401*635a8641SAndroid Build Coastguard Worker 402*635a8641SAndroid Build Coastguard Worker def newline(self, node=None, extra=0): 403*635a8641SAndroid Build Coastguard Worker """Add one or more newlines before the next write.""" 404*635a8641SAndroid Build Coastguard Worker self._new_lines = max(self._new_lines, 1 + extra) 405*635a8641SAndroid Build Coastguard Worker if node is not None and node.lineno != self._last_line: 406*635a8641SAndroid Build Coastguard Worker self._write_debug_info = node.lineno 407*635a8641SAndroid Build Coastguard Worker self._last_line = node.lineno 408*635a8641SAndroid Build Coastguard Worker 409*635a8641SAndroid Build Coastguard Worker def signature(self, node, frame, extra_kwargs=None): 410*635a8641SAndroid Build Coastguard Worker """Writes a function call to the stream for the current node. 411*635a8641SAndroid Build Coastguard Worker A leading comma is added automatically. The extra keyword 412*635a8641SAndroid Build Coastguard Worker arguments may not include python keywords otherwise a syntax 413*635a8641SAndroid Build Coastguard Worker error could occour. The extra keyword arguments should be given 414*635a8641SAndroid Build Coastguard Worker as python dict. 415*635a8641SAndroid Build Coastguard Worker """ 416*635a8641SAndroid Build Coastguard Worker # if any of the given keyword arguments is a python keyword 417*635a8641SAndroid Build Coastguard Worker # we have to make sure that no invalid call is created. 418*635a8641SAndroid Build Coastguard Worker kwarg_workaround = False 419*635a8641SAndroid Build Coastguard Worker for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()): 420*635a8641SAndroid Build Coastguard Worker if is_python_keyword(kwarg): 421*635a8641SAndroid Build Coastguard Worker kwarg_workaround = True 422*635a8641SAndroid Build Coastguard Worker break 423*635a8641SAndroid Build Coastguard Worker 424*635a8641SAndroid Build Coastguard Worker for arg in node.args: 425*635a8641SAndroid Build Coastguard Worker self.write(', ') 426*635a8641SAndroid Build Coastguard Worker self.visit(arg, frame) 427*635a8641SAndroid Build Coastguard Worker 428*635a8641SAndroid Build Coastguard Worker if not kwarg_workaround: 429*635a8641SAndroid Build Coastguard Worker for kwarg in node.kwargs: 430*635a8641SAndroid Build Coastguard Worker self.write(', ') 431*635a8641SAndroid Build Coastguard Worker self.visit(kwarg, frame) 432*635a8641SAndroid Build Coastguard Worker if extra_kwargs is not None: 433*635a8641SAndroid Build Coastguard Worker for key, value in iteritems(extra_kwargs): 434*635a8641SAndroid Build Coastguard Worker self.write(', %s=%s' % (key, value)) 435*635a8641SAndroid Build Coastguard Worker if node.dyn_args: 436*635a8641SAndroid Build Coastguard Worker self.write(', *') 437*635a8641SAndroid Build Coastguard Worker self.visit(node.dyn_args, frame) 438*635a8641SAndroid Build Coastguard Worker 439*635a8641SAndroid Build Coastguard Worker if kwarg_workaround: 440*635a8641SAndroid Build Coastguard Worker if node.dyn_kwargs is not None: 441*635a8641SAndroid Build Coastguard Worker self.write(', **dict({') 442*635a8641SAndroid Build Coastguard Worker else: 443*635a8641SAndroid Build Coastguard Worker self.write(', **{') 444*635a8641SAndroid Build Coastguard Worker for kwarg in node.kwargs: 445*635a8641SAndroid Build Coastguard Worker self.write('%r: ' % kwarg.key) 446*635a8641SAndroid Build Coastguard Worker self.visit(kwarg.value, frame) 447*635a8641SAndroid Build Coastguard Worker self.write(', ') 448*635a8641SAndroid Build Coastguard Worker if extra_kwargs is not None: 449*635a8641SAndroid Build Coastguard Worker for key, value in iteritems(extra_kwargs): 450*635a8641SAndroid Build Coastguard Worker self.write('%r: %s, ' % (key, value)) 451*635a8641SAndroid Build Coastguard Worker if node.dyn_kwargs is not None: 452*635a8641SAndroid Build Coastguard Worker self.write('}, **') 453*635a8641SAndroid Build Coastguard Worker self.visit(node.dyn_kwargs, frame) 454*635a8641SAndroid Build Coastguard Worker self.write(')') 455*635a8641SAndroid Build Coastguard Worker else: 456*635a8641SAndroid Build Coastguard Worker self.write('}') 457*635a8641SAndroid Build Coastguard Worker 458*635a8641SAndroid Build Coastguard Worker elif node.dyn_kwargs is not None: 459*635a8641SAndroid Build Coastguard Worker self.write(', **') 460*635a8641SAndroid Build Coastguard Worker self.visit(node.dyn_kwargs, frame) 461*635a8641SAndroid Build Coastguard Worker 462*635a8641SAndroid Build Coastguard Worker def pull_dependencies(self, nodes): 463*635a8641SAndroid Build Coastguard Worker """Pull all the dependencies.""" 464*635a8641SAndroid Build Coastguard Worker visitor = DependencyFinderVisitor() 465*635a8641SAndroid Build Coastguard Worker for node in nodes: 466*635a8641SAndroid Build Coastguard Worker visitor.visit(node) 467*635a8641SAndroid Build Coastguard Worker for dependency in 'filters', 'tests': 468*635a8641SAndroid Build Coastguard Worker mapping = getattr(self, dependency) 469*635a8641SAndroid Build Coastguard Worker for name in getattr(visitor, dependency): 470*635a8641SAndroid Build Coastguard Worker if name not in mapping: 471*635a8641SAndroid Build Coastguard Worker mapping[name] = self.temporary_identifier() 472*635a8641SAndroid Build Coastguard Worker self.writeline('%s = environment.%s[%r]' % 473*635a8641SAndroid Build Coastguard Worker (mapping[name], dependency, name)) 474*635a8641SAndroid Build Coastguard Worker 475*635a8641SAndroid Build Coastguard Worker def enter_frame(self, frame): 476*635a8641SAndroid Build Coastguard Worker undefs = [] 477*635a8641SAndroid Build Coastguard Worker for target, (action, param) in iteritems(frame.symbols.loads): 478*635a8641SAndroid Build Coastguard Worker if action == VAR_LOAD_PARAMETER: 479*635a8641SAndroid Build Coastguard Worker pass 480*635a8641SAndroid Build Coastguard Worker elif action == VAR_LOAD_RESOLVE: 481*635a8641SAndroid Build Coastguard Worker self.writeline('%s = %s(%r)' % 482*635a8641SAndroid Build Coastguard Worker (target, self.get_resolve_func(), param)) 483*635a8641SAndroid Build Coastguard Worker elif action == VAR_LOAD_ALIAS: 484*635a8641SAndroid Build Coastguard Worker self.writeline('%s = %s' % (target, param)) 485*635a8641SAndroid Build Coastguard Worker elif action == VAR_LOAD_UNDEFINED: 486*635a8641SAndroid Build Coastguard Worker undefs.append(target) 487*635a8641SAndroid Build Coastguard Worker else: 488*635a8641SAndroid Build Coastguard Worker raise NotImplementedError('unknown load instruction') 489*635a8641SAndroid Build Coastguard Worker if undefs: 490*635a8641SAndroid Build Coastguard Worker self.writeline('%s = missing' % ' = '.join(undefs)) 491*635a8641SAndroid Build Coastguard Worker 492*635a8641SAndroid Build Coastguard Worker def leave_frame(self, frame, with_python_scope=False): 493*635a8641SAndroid Build Coastguard Worker if not with_python_scope: 494*635a8641SAndroid Build Coastguard Worker undefs = [] 495*635a8641SAndroid Build Coastguard Worker for target, _ in iteritems(frame.symbols.loads): 496*635a8641SAndroid Build Coastguard Worker undefs.append(target) 497*635a8641SAndroid Build Coastguard Worker if undefs: 498*635a8641SAndroid Build Coastguard Worker self.writeline('%s = missing' % ' = '.join(undefs)) 499*635a8641SAndroid Build Coastguard Worker 500*635a8641SAndroid Build Coastguard Worker def func(self, name): 501*635a8641SAndroid Build Coastguard Worker if self.environment.is_async: 502*635a8641SAndroid Build Coastguard Worker return 'async def %s' % name 503*635a8641SAndroid Build Coastguard Worker return 'def %s' % name 504*635a8641SAndroid Build Coastguard Worker 505*635a8641SAndroid Build Coastguard Worker def macro_body(self, node, frame): 506*635a8641SAndroid Build Coastguard Worker """Dump the function def of a macro or call block.""" 507*635a8641SAndroid Build Coastguard Worker frame = frame.inner() 508*635a8641SAndroid Build Coastguard Worker frame.symbols.analyze_node(node) 509*635a8641SAndroid Build Coastguard Worker macro_ref = MacroRef(node) 510*635a8641SAndroid Build Coastguard Worker 511*635a8641SAndroid Build Coastguard Worker explicit_caller = None 512*635a8641SAndroid Build Coastguard Worker skip_special_params = set() 513*635a8641SAndroid Build Coastguard Worker args = [] 514*635a8641SAndroid Build Coastguard Worker for idx, arg in enumerate(node.args): 515*635a8641SAndroid Build Coastguard Worker if arg.name == 'caller': 516*635a8641SAndroid Build Coastguard Worker explicit_caller = idx 517*635a8641SAndroid Build Coastguard Worker if arg.name in ('kwargs', 'varargs'): 518*635a8641SAndroid Build Coastguard Worker skip_special_params.add(arg.name) 519*635a8641SAndroid Build Coastguard Worker args.append(frame.symbols.ref(arg.name)) 520*635a8641SAndroid Build Coastguard Worker 521*635a8641SAndroid Build Coastguard Worker undeclared = find_undeclared(node.body, ('caller', 'kwargs', 'varargs')) 522*635a8641SAndroid Build Coastguard Worker 523*635a8641SAndroid Build Coastguard Worker if 'caller' in undeclared: 524*635a8641SAndroid Build Coastguard Worker # In older Jinja2 versions there was a bug that allowed caller 525*635a8641SAndroid Build Coastguard Worker # to retain the special behavior even if it was mentioned in 526*635a8641SAndroid Build Coastguard Worker # the argument list. However thankfully this was only really 527*635a8641SAndroid Build Coastguard Worker # working if it was the last argument. So we are explicitly 528*635a8641SAndroid Build Coastguard Worker # checking this now and error out if it is anywhere else in 529*635a8641SAndroid Build Coastguard Worker # the argument list. 530*635a8641SAndroid Build Coastguard Worker if explicit_caller is not None: 531*635a8641SAndroid Build Coastguard Worker try: 532*635a8641SAndroid Build Coastguard Worker node.defaults[explicit_caller - len(node.args)] 533*635a8641SAndroid Build Coastguard Worker except IndexError: 534*635a8641SAndroid Build Coastguard Worker self.fail('When defining macros or call blocks the ' 535*635a8641SAndroid Build Coastguard Worker 'special "caller" argument must be omitted ' 536*635a8641SAndroid Build Coastguard Worker 'or be given a default.', node.lineno) 537*635a8641SAndroid Build Coastguard Worker else: 538*635a8641SAndroid Build Coastguard Worker args.append(frame.symbols.declare_parameter('caller')) 539*635a8641SAndroid Build Coastguard Worker macro_ref.accesses_caller = True 540*635a8641SAndroid Build Coastguard Worker if 'kwargs' in undeclared and not 'kwargs' in skip_special_params: 541*635a8641SAndroid Build Coastguard Worker args.append(frame.symbols.declare_parameter('kwargs')) 542*635a8641SAndroid Build Coastguard Worker macro_ref.accesses_kwargs = True 543*635a8641SAndroid Build Coastguard Worker if 'varargs' in undeclared and not 'varargs' in skip_special_params: 544*635a8641SAndroid Build Coastguard Worker args.append(frame.symbols.declare_parameter('varargs')) 545*635a8641SAndroid Build Coastguard Worker macro_ref.accesses_varargs = True 546*635a8641SAndroid Build Coastguard Worker 547*635a8641SAndroid Build Coastguard Worker # macros are delayed, they never require output checks 548*635a8641SAndroid Build Coastguard Worker frame.require_output_check = False 549*635a8641SAndroid Build Coastguard Worker frame.symbols.analyze_node(node) 550*635a8641SAndroid Build Coastguard Worker self.writeline('%s(%s):' % (self.func('macro'), ', '.join(args)), node) 551*635a8641SAndroid Build Coastguard Worker self.indent() 552*635a8641SAndroid Build Coastguard Worker 553*635a8641SAndroid Build Coastguard Worker self.buffer(frame) 554*635a8641SAndroid Build Coastguard Worker self.enter_frame(frame) 555*635a8641SAndroid Build Coastguard Worker 556*635a8641SAndroid Build Coastguard Worker self.push_parameter_definitions(frame) 557*635a8641SAndroid Build Coastguard Worker for idx, arg in enumerate(node.args): 558*635a8641SAndroid Build Coastguard Worker ref = frame.symbols.ref(arg.name) 559*635a8641SAndroid Build Coastguard Worker self.writeline('if %s is missing:' % ref) 560*635a8641SAndroid Build Coastguard Worker self.indent() 561*635a8641SAndroid Build Coastguard Worker try: 562*635a8641SAndroid Build Coastguard Worker default = node.defaults[idx - len(node.args)] 563*635a8641SAndroid Build Coastguard Worker except IndexError: 564*635a8641SAndroid Build Coastguard Worker self.writeline('%s = undefined(%r, name=%r)' % ( 565*635a8641SAndroid Build Coastguard Worker ref, 566*635a8641SAndroid Build Coastguard Worker 'parameter %r was not provided' % arg.name, 567*635a8641SAndroid Build Coastguard Worker arg.name)) 568*635a8641SAndroid Build Coastguard Worker else: 569*635a8641SAndroid Build Coastguard Worker self.writeline('%s = ' % ref) 570*635a8641SAndroid Build Coastguard Worker self.visit(default, frame) 571*635a8641SAndroid Build Coastguard Worker self.mark_parameter_stored(ref) 572*635a8641SAndroid Build Coastguard Worker self.outdent() 573*635a8641SAndroid Build Coastguard Worker self.pop_parameter_definitions() 574*635a8641SAndroid Build Coastguard Worker 575*635a8641SAndroid Build Coastguard Worker self.blockvisit(node.body, frame) 576*635a8641SAndroid Build Coastguard Worker self.return_buffer_contents(frame, force_unescaped=True) 577*635a8641SAndroid Build Coastguard Worker self.leave_frame(frame, with_python_scope=True) 578*635a8641SAndroid Build Coastguard Worker self.outdent() 579*635a8641SAndroid Build Coastguard Worker 580*635a8641SAndroid Build Coastguard Worker return frame, macro_ref 581*635a8641SAndroid Build Coastguard Worker 582*635a8641SAndroid Build Coastguard Worker def macro_def(self, macro_ref, frame): 583*635a8641SAndroid Build Coastguard Worker """Dump the macro definition for the def created by macro_body.""" 584*635a8641SAndroid Build Coastguard Worker arg_tuple = ', '.join(repr(x.name) for x in macro_ref.node.args) 585*635a8641SAndroid Build Coastguard Worker name = getattr(macro_ref.node, 'name', None) 586*635a8641SAndroid Build Coastguard Worker if len(macro_ref.node.args) == 1: 587*635a8641SAndroid Build Coastguard Worker arg_tuple += ',' 588*635a8641SAndroid Build Coastguard Worker self.write('Macro(environment, macro, %r, (%s), %r, %r, %r, ' 589*635a8641SAndroid Build Coastguard Worker 'context.eval_ctx.autoescape)' % 590*635a8641SAndroid Build Coastguard Worker (name, arg_tuple, macro_ref.accesses_kwargs, 591*635a8641SAndroid Build Coastguard Worker macro_ref.accesses_varargs, macro_ref.accesses_caller)) 592*635a8641SAndroid Build Coastguard Worker 593*635a8641SAndroid Build Coastguard Worker def position(self, node): 594*635a8641SAndroid Build Coastguard Worker """Return a human readable position for the node.""" 595*635a8641SAndroid Build Coastguard Worker rv = 'line %d' % node.lineno 596*635a8641SAndroid Build Coastguard Worker if self.name is not None: 597*635a8641SAndroid Build Coastguard Worker rv += ' in ' + repr(self.name) 598*635a8641SAndroid Build Coastguard Worker return rv 599*635a8641SAndroid Build Coastguard Worker 600*635a8641SAndroid Build Coastguard Worker def dump_local_context(self, frame): 601*635a8641SAndroid Build Coastguard Worker return '{%s}' % ', '.join( 602*635a8641SAndroid Build Coastguard Worker '%r: %s' % (name, target) for name, target 603*635a8641SAndroid Build Coastguard Worker in iteritems(frame.symbols.dump_stores())) 604*635a8641SAndroid Build Coastguard Worker 605*635a8641SAndroid Build Coastguard Worker def write_commons(self): 606*635a8641SAndroid Build Coastguard Worker """Writes a common preamble that is used by root and block functions. 607*635a8641SAndroid Build Coastguard Worker Primarily this sets up common local helpers and enforces a generator 608*635a8641SAndroid Build Coastguard Worker through a dead branch. 609*635a8641SAndroid Build Coastguard Worker """ 610*635a8641SAndroid Build Coastguard Worker self.writeline('resolve = context.resolve_or_missing') 611*635a8641SAndroid Build Coastguard Worker self.writeline('undefined = environment.undefined') 612*635a8641SAndroid Build Coastguard Worker self.writeline('if 0: yield None') 613*635a8641SAndroid Build Coastguard Worker 614*635a8641SAndroid Build Coastguard Worker def push_parameter_definitions(self, frame): 615*635a8641SAndroid Build Coastguard Worker """Pushes all parameter targets from the given frame into a local 616*635a8641SAndroid Build Coastguard Worker stack that permits tracking of yet to be assigned parameters. In 617*635a8641SAndroid Build Coastguard Worker particular this enables the optimization from `visit_Name` to skip 618*635a8641SAndroid Build Coastguard Worker undefined expressions for parameters in macros as macros can reference 619*635a8641SAndroid Build Coastguard Worker otherwise unbound parameters. 620*635a8641SAndroid Build Coastguard Worker """ 621*635a8641SAndroid Build Coastguard Worker self._param_def_block.append(frame.symbols.dump_param_targets()) 622*635a8641SAndroid Build Coastguard Worker 623*635a8641SAndroid Build Coastguard Worker def pop_parameter_definitions(self): 624*635a8641SAndroid Build Coastguard Worker """Pops the current parameter definitions set.""" 625*635a8641SAndroid Build Coastguard Worker self._param_def_block.pop() 626*635a8641SAndroid Build Coastguard Worker 627*635a8641SAndroid Build Coastguard Worker def mark_parameter_stored(self, target): 628*635a8641SAndroid Build Coastguard Worker """Marks a parameter in the current parameter definitions as stored. 629*635a8641SAndroid Build Coastguard Worker This will skip the enforced undefined checks. 630*635a8641SAndroid Build Coastguard Worker """ 631*635a8641SAndroid Build Coastguard Worker if self._param_def_block: 632*635a8641SAndroid Build Coastguard Worker self._param_def_block[-1].discard(target) 633*635a8641SAndroid Build Coastguard Worker 634*635a8641SAndroid Build Coastguard Worker def push_context_reference(self, target): 635*635a8641SAndroid Build Coastguard Worker self._context_reference_stack.append(target) 636*635a8641SAndroid Build Coastguard Worker 637*635a8641SAndroid Build Coastguard Worker def pop_context_reference(self): 638*635a8641SAndroid Build Coastguard Worker self._context_reference_stack.pop() 639*635a8641SAndroid Build Coastguard Worker 640*635a8641SAndroid Build Coastguard Worker def get_context_ref(self): 641*635a8641SAndroid Build Coastguard Worker return self._context_reference_stack[-1] 642*635a8641SAndroid Build Coastguard Worker 643*635a8641SAndroid Build Coastguard Worker def get_resolve_func(self): 644*635a8641SAndroid Build Coastguard Worker target = self._context_reference_stack[-1] 645*635a8641SAndroid Build Coastguard Worker if target == 'context': 646*635a8641SAndroid Build Coastguard Worker return 'resolve' 647*635a8641SAndroid Build Coastguard Worker return '%s.resolve' % target 648*635a8641SAndroid Build Coastguard Worker 649*635a8641SAndroid Build Coastguard Worker def derive_context(self, frame): 650*635a8641SAndroid Build Coastguard Worker return '%s.derived(%s)' % ( 651*635a8641SAndroid Build Coastguard Worker self.get_context_ref(), 652*635a8641SAndroid Build Coastguard Worker self.dump_local_context(frame), 653*635a8641SAndroid Build Coastguard Worker ) 654*635a8641SAndroid Build Coastguard Worker 655*635a8641SAndroid Build Coastguard Worker def parameter_is_undeclared(self, target): 656*635a8641SAndroid Build Coastguard Worker """Checks if a given target is an undeclared parameter.""" 657*635a8641SAndroid Build Coastguard Worker if not self._param_def_block: 658*635a8641SAndroid Build Coastguard Worker return False 659*635a8641SAndroid Build Coastguard Worker return target in self._param_def_block[-1] 660*635a8641SAndroid Build Coastguard Worker 661*635a8641SAndroid Build Coastguard Worker def push_assign_tracking(self): 662*635a8641SAndroid Build Coastguard Worker """Pushes a new layer for assignment tracking.""" 663*635a8641SAndroid Build Coastguard Worker self._assign_stack.append(set()) 664*635a8641SAndroid Build Coastguard Worker 665*635a8641SAndroid Build Coastguard Worker def pop_assign_tracking(self, frame): 666*635a8641SAndroid Build Coastguard Worker """Pops the topmost level for assignment tracking and updates the 667*635a8641SAndroid Build Coastguard Worker context variables if necessary. 668*635a8641SAndroid Build Coastguard Worker """ 669*635a8641SAndroid Build Coastguard Worker vars = self._assign_stack.pop() 670*635a8641SAndroid Build Coastguard Worker if not frame.toplevel or not vars: 671*635a8641SAndroid Build Coastguard Worker return 672*635a8641SAndroid Build Coastguard Worker public_names = [x for x in vars if x[:1] != '_'] 673*635a8641SAndroid Build Coastguard Worker if len(vars) == 1: 674*635a8641SAndroid Build Coastguard Worker name = next(iter(vars)) 675*635a8641SAndroid Build Coastguard Worker ref = frame.symbols.ref(name) 676*635a8641SAndroid Build Coastguard Worker self.writeline('context.vars[%r] = %s' % (name, ref)) 677*635a8641SAndroid Build Coastguard Worker else: 678*635a8641SAndroid Build Coastguard Worker self.writeline('context.vars.update({') 679*635a8641SAndroid Build Coastguard Worker for idx, name in enumerate(vars): 680*635a8641SAndroid Build Coastguard Worker if idx: 681*635a8641SAndroid Build Coastguard Worker self.write(', ') 682*635a8641SAndroid Build Coastguard Worker ref = frame.symbols.ref(name) 683*635a8641SAndroid Build Coastguard Worker self.write('%r: %s' % (name, ref)) 684*635a8641SAndroid Build Coastguard Worker self.write('})') 685*635a8641SAndroid Build Coastguard Worker if public_names: 686*635a8641SAndroid Build Coastguard Worker if len(public_names) == 1: 687*635a8641SAndroid Build Coastguard Worker self.writeline('context.exported_vars.add(%r)' % 688*635a8641SAndroid Build Coastguard Worker public_names[0]) 689*635a8641SAndroid Build Coastguard Worker else: 690*635a8641SAndroid Build Coastguard Worker self.writeline('context.exported_vars.update((%s))' % 691*635a8641SAndroid Build Coastguard Worker ', '.join(imap(repr, public_names))) 692*635a8641SAndroid Build Coastguard Worker 693*635a8641SAndroid Build Coastguard Worker # -- Statement Visitors 694*635a8641SAndroid Build Coastguard Worker 695*635a8641SAndroid Build Coastguard Worker def visit_Template(self, node, frame=None): 696*635a8641SAndroid Build Coastguard Worker assert frame is None, 'no root frame allowed' 697*635a8641SAndroid Build Coastguard Worker eval_ctx = EvalContext(self.environment, self.name) 698*635a8641SAndroid Build Coastguard Worker 699*635a8641SAndroid Build Coastguard Worker from jinja2.runtime import __all__ as exported 700*635a8641SAndroid Build Coastguard Worker self.writeline('from __future__ import %s' % ', '.join(code_features)) 701*635a8641SAndroid Build Coastguard Worker self.writeline('from jinja2.runtime import ' + ', '.join(exported)) 702*635a8641SAndroid Build Coastguard Worker 703*635a8641SAndroid Build Coastguard Worker if self.environment.is_async: 704*635a8641SAndroid Build Coastguard Worker self.writeline('from jinja2.asyncsupport import auto_await, ' 705*635a8641SAndroid Build Coastguard Worker 'auto_aiter, make_async_loop_context') 706*635a8641SAndroid Build Coastguard Worker 707*635a8641SAndroid Build Coastguard Worker # if we want a deferred initialization we cannot move the 708*635a8641SAndroid Build Coastguard Worker # environment into a local name 709*635a8641SAndroid Build Coastguard Worker envenv = not self.defer_init and ', environment=environment' or '' 710*635a8641SAndroid Build Coastguard Worker 711*635a8641SAndroid Build Coastguard Worker # do we have an extends tag at all? If not, we can save some 712*635a8641SAndroid Build Coastguard Worker # overhead by just not processing any inheritance code. 713*635a8641SAndroid Build Coastguard Worker have_extends = node.find(nodes.Extends) is not None 714*635a8641SAndroid Build Coastguard Worker 715*635a8641SAndroid Build Coastguard Worker # find all blocks 716*635a8641SAndroid Build Coastguard Worker for block in node.find_all(nodes.Block): 717*635a8641SAndroid Build Coastguard Worker if block.name in self.blocks: 718*635a8641SAndroid Build Coastguard Worker self.fail('block %r defined twice' % block.name, block.lineno) 719*635a8641SAndroid Build Coastguard Worker self.blocks[block.name] = block 720*635a8641SAndroid Build Coastguard Worker 721*635a8641SAndroid Build Coastguard Worker # find all imports and import them 722*635a8641SAndroid Build Coastguard Worker for import_ in node.find_all(nodes.ImportedName): 723*635a8641SAndroid Build Coastguard Worker if import_.importname not in self.import_aliases: 724*635a8641SAndroid Build Coastguard Worker imp = import_.importname 725*635a8641SAndroid Build Coastguard Worker self.import_aliases[imp] = alias = self.temporary_identifier() 726*635a8641SAndroid Build Coastguard Worker if '.' in imp: 727*635a8641SAndroid Build Coastguard Worker module, obj = imp.rsplit('.', 1) 728*635a8641SAndroid Build Coastguard Worker self.writeline('from %s import %s as %s' % 729*635a8641SAndroid Build Coastguard Worker (module, obj, alias)) 730*635a8641SAndroid Build Coastguard Worker else: 731*635a8641SAndroid Build Coastguard Worker self.writeline('import %s as %s' % (imp, alias)) 732*635a8641SAndroid Build Coastguard Worker 733*635a8641SAndroid Build Coastguard Worker # add the load name 734*635a8641SAndroid Build Coastguard Worker self.writeline('name = %r' % self.name) 735*635a8641SAndroid Build Coastguard Worker 736*635a8641SAndroid Build Coastguard Worker # generate the root render function. 737*635a8641SAndroid Build Coastguard Worker self.writeline('%s(context, missing=missing%s):' % 738*635a8641SAndroid Build Coastguard Worker (self.func('root'), envenv), extra=1) 739*635a8641SAndroid Build Coastguard Worker self.indent() 740*635a8641SAndroid Build Coastguard Worker self.write_commons() 741*635a8641SAndroid Build Coastguard Worker 742*635a8641SAndroid Build Coastguard Worker # process the root 743*635a8641SAndroid Build Coastguard Worker frame = Frame(eval_ctx) 744*635a8641SAndroid Build Coastguard Worker if 'self' in find_undeclared(node.body, ('self',)): 745*635a8641SAndroid Build Coastguard Worker ref = frame.symbols.declare_parameter('self') 746*635a8641SAndroid Build Coastguard Worker self.writeline('%s = TemplateReference(context)' % ref) 747*635a8641SAndroid Build Coastguard Worker frame.symbols.analyze_node(node) 748*635a8641SAndroid Build Coastguard Worker frame.toplevel = frame.rootlevel = True 749*635a8641SAndroid Build Coastguard Worker frame.require_output_check = have_extends and not self.has_known_extends 750*635a8641SAndroid Build Coastguard Worker if have_extends: 751*635a8641SAndroid Build Coastguard Worker self.writeline('parent_template = None') 752*635a8641SAndroid Build Coastguard Worker self.enter_frame(frame) 753*635a8641SAndroid Build Coastguard Worker self.pull_dependencies(node.body) 754*635a8641SAndroid Build Coastguard Worker self.blockvisit(node.body, frame) 755*635a8641SAndroid Build Coastguard Worker self.leave_frame(frame, with_python_scope=True) 756*635a8641SAndroid Build Coastguard Worker self.outdent() 757*635a8641SAndroid Build Coastguard Worker 758*635a8641SAndroid Build Coastguard Worker # make sure that the parent root is called. 759*635a8641SAndroid Build Coastguard Worker if have_extends: 760*635a8641SAndroid Build Coastguard Worker if not self.has_known_extends: 761*635a8641SAndroid Build Coastguard Worker self.indent() 762*635a8641SAndroid Build Coastguard Worker self.writeline('if parent_template is not None:') 763*635a8641SAndroid Build Coastguard Worker self.indent() 764*635a8641SAndroid Build Coastguard Worker if supports_yield_from and not self.environment.is_async: 765*635a8641SAndroid Build Coastguard Worker self.writeline('yield from parent_template.' 766*635a8641SAndroid Build Coastguard Worker 'root_render_func(context)') 767*635a8641SAndroid Build Coastguard Worker else: 768*635a8641SAndroid Build Coastguard Worker self.writeline('%sfor event in parent_template.' 769*635a8641SAndroid Build Coastguard Worker 'root_render_func(context):' % 770*635a8641SAndroid Build Coastguard Worker (self.environment.is_async and 'async ' or '')) 771*635a8641SAndroid Build Coastguard Worker self.indent() 772*635a8641SAndroid Build Coastguard Worker self.writeline('yield event') 773*635a8641SAndroid Build Coastguard Worker self.outdent() 774*635a8641SAndroid Build Coastguard Worker self.outdent(1 + (not self.has_known_extends)) 775*635a8641SAndroid Build Coastguard Worker 776*635a8641SAndroid Build Coastguard Worker # at this point we now have the blocks collected and can visit them too. 777*635a8641SAndroid Build Coastguard Worker for name, block in iteritems(self.blocks): 778*635a8641SAndroid Build Coastguard Worker self.writeline('%s(context, missing=missing%s):' % 779*635a8641SAndroid Build Coastguard Worker (self.func('block_' + name), envenv), 780*635a8641SAndroid Build Coastguard Worker block, 1) 781*635a8641SAndroid Build Coastguard Worker self.indent() 782*635a8641SAndroid Build Coastguard Worker self.write_commons() 783*635a8641SAndroid Build Coastguard Worker # It's important that we do not make this frame a child of the 784*635a8641SAndroid Build Coastguard Worker # toplevel template. This would cause a variety of 785*635a8641SAndroid Build Coastguard Worker # interesting issues with identifier tracking. 786*635a8641SAndroid Build Coastguard Worker block_frame = Frame(eval_ctx) 787*635a8641SAndroid Build Coastguard Worker undeclared = find_undeclared(block.body, ('self', 'super')) 788*635a8641SAndroid Build Coastguard Worker if 'self' in undeclared: 789*635a8641SAndroid Build Coastguard Worker ref = block_frame.symbols.declare_parameter('self') 790*635a8641SAndroid Build Coastguard Worker self.writeline('%s = TemplateReference(context)' % ref) 791*635a8641SAndroid Build Coastguard Worker if 'super' in undeclared: 792*635a8641SAndroid Build Coastguard Worker ref = block_frame.symbols.declare_parameter('super') 793*635a8641SAndroid Build Coastguard Worker self.writeline('%s = context.super(%r, ' 794*635a8641SAndroid Build Coastguard Worker 'block_%s)' % (ref, name, name)) 795*635a8641SAndroid Build Coastguard Worker block_frame.symbols.analyze_node(block) 796*635a8641SAndroid Build Coastguard Worker block_frame.block = name 797*635a8641SAndroid Build Coastguard Worker self.enter_frame(block_frame) 798*635a8641SAndroid Build Coastguard Worker self.pull_dependencies(block.body) 799*635a8641SAndroid Build Coastguard Worker self.blockvisit(block.body, block_frame) 800*635a8641SAndroid Build Coastguard Worker self.leave_frame(block_frame, with_python_scope=True) 801*635a8641SAndroid Build Coastguard Worker self.outdent() 802*635a8641SAndroid Build Coastguard Worker 803*635a8641SAndroid Build Coastguard Worker self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x) 804*635a8641SAndroid Build Coastguard Worker for x in self.blocks), 805*635a8641SAndroid Build Coastguard Worker extra=1) 806*635a8641SAndroid Build Coastguard Worker 807*635a8641SAndroid Build Coastguard Worker # add a function that returns the debug info 808*635a8641SAndroid Build Coastguard Worker self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x 809*635a8641SAndroid Build Coastguard Worker in self.debug_info)) 810*635a8641SAndroid Build Coastguard Worker 811*635a8641SAndroid Build Coastguard Worker def visit_Block(self, node, frame): 812*635a8641SAndroid Build Coastguard Worker """Call a block and register it for the template.""" 813*635a8641SAndroid Build Coastguard Worker level = 0 814*635a8641SAndroid Build Coastguard Worker if frame.toplevel: 815*635a8641SAndroid Build Coastguard Worker # if we know that we are a child template, there is no need to 816*635a8641SAndroid Build Coastguard Worker # check if we are one 817*635a8641SAndroid Build Coastguard Worker if self.has_known_extends: 818*635a8641SAndroid Build Coastguard Worker return 819*635a8641SAndroid Build Coastguard Worker if self.extends_so_far > 0: 820*635a8641SAndroid Build Coastguard Worker self.writeline('if parent_template is None:') 821*635a8641SAndroid Build Coastguard Worker self.indent() 822*635a8641SAndroid Build Coastguard Worker level += 1 823*635a8641SAndroid Build Coastguard Worker 824*635a8641SAndroid Build Coastguard Worker if node.scoped: 825*635a8641SAndroid Build Coastguard Worker context = self.derive_context(frame) 826*635a8641SAndroid Build Coastguard Worker else: 827*635a8641SAndroid Build Coastguard Worker context = self.get_context_ref() 828*635a8641SAndroid Build Coastguard Worker 829*635a8641SAndroid Build Coastguard Worker if supports_yield_from and not self.environment.is_async and \ 830*635a8641SAndroid Build Coastguard Worker frame.buffer is None: 831*635a8641SAndroid Build Coastguard Worker self.writeline('yield from context.blocks[%r][0](%s)' % ( 832*635a8641SAndroid Build Coastguard Worker node.name, context), node) 833*635a8641SAndroid Build Coastguard Worker else: 834*635a8641SAndroid Build Coastguard Worker loop = self.environment.is_async and 'async for' or 'for' 835*635a8641SAndroid Build Coastguard Worker self.writeline('%s event in context.blocks[%r][0](%s):' % ( 836*635a8641SAndroid Build Coastguard Worker loop, node.name, context), node) 837*635a8641SAndroid Build Coastguard Worker self.indent() 838*635a8641SAndroid Build Coastguard Worker self.simple_write('event', frame) 839*635a8641SAndroid Build Coastguard Worker self.outdent() 840*635a8641SAndroid Build Coastguard Worker 841*635a8641SAndroid Build Coastguard Worker self.outdent(level) 842*635a8641SAndroid Build Coastguard Worker 843*635a8641SAndroid Build Coastguard Worker def visit_Extends(self, node, frame): 844*635a8641SAndroid Build Coastguard Worker """Calls the extender.""" 845*635a8641SAndroid Build Coastguard Worker if not frame.toplevel: 846*635a8641SAndroid Build Coastguard Worker self.fail('cannot use extend from a non top-level scope', 847*635a8641SAndroid Build Coastguard Worker node.lineno) 848*635a8641SAndroid Build Coastguard Worker 849*635a8641SAndroid Build Coastguard Worker # if the number of extends statements in general is zero so 850*635a8641SAndroid Build Coastguard Worker # far, we don't have to add a check if something extended 851*635a8641SAndroid Build Coastguard Worker # the template before this one. 852*635a8641SAndroid Build Coastguard Worker if self.extends_so_far > 0: 853*635a8641SAndroid Build Coastguard Worker 854*635a8641SAndroid Build Coastguard Worker # if we have a known extends we just add a template runtime 855*635a8641SAndroid Build Coastguard Worker # error into the generated code. We could catch that at compile 856*635a8641SAndroid Build Coastguard Worker # time too, but i welcome it not to confuse users by throwing the 857*635a8641SAndroid Build Coastguard Worker # same error at different times just "because we can". 858*635a8641SAndroid Build Coastguard Worker if not self.has_known_extends: 859*635a8641SAndroid Build Coastguard Worker self.writeline('if parent_template is not None:') 860*635a8641SAndroid Build Coastguard Worker self.indent() 861*635a8641SAndroid Build Coastguard Worker self.writeline('raise TemplateRuntimeError(%r)' % 862*635a8641SAndroid Build Coastguard Worker 'extended multiple times') 863*635a8641SAndroid Build Coastguard Worker 864*635a8641SAndroid Build Coastguard Worker # if we have a known extends already we don't need that code here 865*635a8641SAndroid Build Coastguard Worker # as we know that the template execution will end here. 866*635a8641SAndroid Build Coastguard Worker if self.has_known_extends: 867*635a8641SAndroid Build Coastguard Worker raise CompilerExit() 868*635a8641SAndroid Build Coastguard Worker else: 869*635a8641SAndroid Build Coastguard Worker self.outdent() 870*635a8641SAndroid Build Coastguard Worker 871*635a8641SAndroid Build Coastguard Worker self.writeline('parent_template = environment.get_template(', node) 872*635a8641SAndroid Build Coastguard Worker self.visit(node.template, frame) 873*635a8641SAndroid Build Coastguard Worker self.write(', %r)' % self.name) 874*635a8641SAndroid Build Coastguard Worker self.writeline('for name, parent_block in parent_template.' 875*635a8641SAndroid Build Coastguard Worker 'blocks.%s():' % dict_item_iter) 876*635a8641SAndroid Build Coastguard Worker self.indent() 877*635a8641SAndroid Build Coastguard Worker self.writeline('context.blocks.setdefault(name, []).' 878*635a8641SAndroid Build Coastguard Worker 'append(parent_block)') 879*635a8641SAndroid Build Coastguard Worker self.outdent() 880*635a8641SAndroid Build Coastguard Worker 881*635a8641SAndroid Build Coastguard Worker # if this extends statement was in the root level we can take 882*635a8641SAndroid Build Coastguard Worker # advantage of that information and simplify the generated code 883*635a8641SAndroid Build Coastguard Worker # in the top level from this point onwards 884*635a8641SAndroid Build Coastguard Worker if frame.rootlevel: 885*635a8641SAndroid Build Coastguard Worker self.has_known_extends = True 886*635a8641SAndroid Build Coastguard Worker 887*635a8641SAndroid Build Coastguard Worker # and now we have one more 888*635a8641SAndroid Build Coastguard Worker self.extends_so_far += 1 889*635a8641SAndroid Build Coastguard Worker 890*635a8641SAndroid Build Coastguard Worker def visit_Include(self, node, frame): 891*635a8641SAndroid Build Coastguard Worker """Handles includes.""" 892*635a8641SAndroid Build Coastguard Worker if node.ignore_missing: 893*635a8641SAndroid Build Coastguard Worker self.writeline('try:') 894*635a8641SAndroid Build Coastguard Worker self.indent() 895*635a8641SAndroid Build Coastguard Worker 896*635a8641SAndroid Build Coastguard Worker func_name = 'get_or_select_template' 897*635a8641SAndroid Build Coastguard Worker if isinstance(node.template, nodes.Const): 898*635a8641SAndroid Build Coastguard Worker if isinstance(node.template.value, string_types): 899*635a8641SAndroid Build Coastguard Worker func_name = 'get_template' 900*635a8641SAndroid Build Coastguard Worker elif isinstance(node.template.value, (tuple, list)): 901*635a8641SAndroid Build Coastguard Worker func_name = 'select_template' 902*635a8641SAndroid Build Coastguard Worker elif isinstance(node.template, (nodes.Tuple, nodes.List)): 903*635a8641SAndroid Build Coastguard Worker func_name = 'select_template' 904*635a8641SAndroid Build Coastguard Worker 905*635a8641SAndroid Build Coastguard Worker self.writeline('template = environment.%s(' % func_name, node) 906*635a8641SAndroid Build Coastguard Worker self.visit(node.template, frame) 907*635a8641SAndroid Build Coastguard Worker self.write(', %r)' % self.name) 908*635a8641SAndroid Build Coastguard Worker if node.ignore_missing: 909*635a8641SAndroid Build Coastguard Worker self.outdent() 910*635a8641SAndroid Build Coastguard Worker self.writeline('except TemplateNotFound:') 911*635a8641SAndroid Build Coastguard Worker self.indent() 912*635a8641SAndroid Build Coastguard Worker self.writeline('pass') 913*635a8641SAndroid Build Coastguard Worker self.outdent() 914*635a8641SAndroid Build Coastguard Worker self.writeline('else:') 915*635a8641SAndroid Build Coastguard Worker self.indent() 916*635a8641SAndroid Build Coastguard Worker 917*635a8641SAndroid Build Coastguard Worker skip_event_yield = False 918*635a8641SAndroid Build Coastguard Worker if node.with_context: 919*635a8641SAndroid Build Coastguard Worker loop = self.environment.is_async and 'async for' or 'for' 920*635a8641SAndroid Build Coastguard Worker self.writeline('%s event in template.root_render_func(' 921*635a8641SAndroid Build Coastguard Worker 'template.new_context(context.get_all(), True, ' 922*635a8641SAndroid Build Coastguard Worker '%s)):' % (loop, self.dump_local_context(frame))) 923*635a8641SAndroid Build Coastguard Worker elif self.environment.is_async: 924*635a8641SAndroid Build Coastguard Worker self.writeline('for event in (await ' 925*635a8641SAndroid Build Coastguard Worker 'template._get_default_module_async())' 926*635a8641SAndroid Build Coastguard Worker '._body_stream:') 927*635a8641SAndroid Build Coastguard Worker else: 928*635a8641SAndroid Build Coastguard Worker if supports_yield_from: 929*635a8641SAndroid Build Coastguard Worker self.writeline('yield from template._get_default_module()' 930*635a8641SAndroid Build Coastguard Worker '._body_stream') 931*635a8641SAndroid Build Coastguard Worker skip_event_yield = True 932*635a8641SAndroid Build Coastguard Worker else: 933*635a8641SAndroid Build Coastguard Worker self.writeline('for event in template._get_default_module()' 934*635a8641SAndroid Build Coastguard Worker '._body_stream:') 935*635a8641SAndroid Build Coastguard Worker 936*635a8641SAndroid Build Coastguard Worker if not skip_event_yield: 937*635a8641SAndroid Build Coastguard Worker self.indent() 938*635a8641SAndroid Build Coastguard Worker self.simple_write('event', frame) 939*635a8641SAndroid Build Coastguard Worker self.outdent() 940*635a8641SAndroid Build Coastguard Worker 941*635a8641SAndroid Build Coastguard Worker if node.ignore_missing: 942*635a8641SAndroid Build Coastguard Worker self.outdent() 943*635a8641SAndroid Build Coastguard Worker 944*635a8641SAndroid Build Coastguard Worker def visit_Import(self, node, frame): 945*635a8641SAndroid Build Coastguard Worker """Visit regular imports.""" 946*635a8641SAndroid Build Coastguard Worker self.writeline('%s = ' % frame.symbols.ref(node.target), node) 947*635a8641SAndroid Build Coastguard Worker if frame.toplevel: 948*635a8641SAndroid Build Coastguard Worker self.write('context.vars[%r] = ' % node.target) 949*635a8641SAndroid Build Coastguard Worker if self.environment.is_async: 950*635a8641SAndroid Build Coastguard Worker self.write('await ') 951*635a8641SAndroid Build Coastguard Worker self.write('environment.get_template(') 952*635a8641SAndroid Build Coastguard Worker self.visit(node.template, frame) 953*635a8641SAndroid Build Coastguard Worker self.write(', %r).' % self.name) 954*635a8641SAndroid Build Coastguard Worker if node.with_context: 955*635a8641SAndroid Build Coastguard Worker self.write('make_module%s(context.get_all(), True, %s)' 956*635a8641SAndroid Build Coastguard Worker % (self.environment.is_async and '_async' or '', 957*635a8641SAndroid Build Coastguard Worker self.dump_local_context(frame))) 958*635a8641SAndroid Build Coastguard Worker elif self.environment.is_async: 959*635a8641SAndroid Build Coastguard Worker self.write('_get_default_module_async()') 960*635a8641SAndroid Build Coastguard Worker else: 961*635a8641SAndroid Build Coastguard Worker self.write('_get_default_module()') 962*635a8641SAndroid Build Coastguard Worker if frame.toplevel and not node.target.startswith('_'): 963*635a8641SAndroid Build Coastguard Worker self.writeline('context.exported_vars.discard(%r)' % node.target) 964*635a8641SAndroid Build Coastguard Worker 965*635a8641SAndroid Build Coastguard Worker def visit_FromImport(self, node, frame): 966*635a8641SAndroid Build Coastguard Worker """Visit named imports.""" 967*635a8641SAndroid Build Coastguard Worker self.newline(node) 968*635a8641SAndroid Build Coastguard Worker self.write('included_template = %senvironment.get_template(' 969*635a8641SAndroid Build Coastguard Worker % (self.environment.is_async and 'await ' or '')) 970*635a8641SAndroid Build Coastguard Worker self.visit(node.template, frame) 971*635a8641SAndroid Build Coastguard Worker self.write(', %r).' % self.name) 972*635a8641SAndroid Build Coastguard Worker if node.with_context: 973*635a8641SAndroid Build Coastguard Worker self.write('make_module%s(context.get_all(), True, %s)' 974*635a8641SAndroid Build Coastguard Worker % (self.environment.is_async and '_async' or '', 975*635a8641SAndroid Build Coastguard Worker self.dump_local_context(frame))) 976*635a8641SAndroid Build Coastguard Worker elif self.environment.is_async: 977*635a8641SAndroid Build Coastguard Worker self.write('_get_default_module_async()') 978*635a8641SAndroid Build Coastguard Worker else: 979*635a8641SAndroid Build Coastguard Worker self.write('_get_default_module()') 980*635a8641SAndroid Build Coastguard Worker 981*635a8641SAndroid Build Coastguard Worker var_names = [] 982*635a8641SAndroid Build Coastguard Worker discarded_names = [] 983*635a8641SAndroid Build Coastguard Worker for name in node.names: 984*635a8641SAndroid Build Coastguard Worker if isinstance(name, tuple): 985*635a8641SAndroid Build Coastguard Worker name, alias = name 986*635a8641SAndroid Build Coastguard Worker else: 987*635a8641SAndroid Build Coastguard Worker alias = name 988*635a8641SAndroid Build Coastguard Worker self.writeline('%s = getattr(included_template, ' 989*635a8641SAndroid Build Coastguard Worker '%r, missing)' % (frame.symbols.ref(alias), name)) 990*635a8641SAndroid Build Coastguard Worker self.writeline('if %s is missing:' % frame.symbols.ref(alias)) 991*635a8641SAndroid Build Coastguard Worker self.indent() 992*635a8641SAndroid Build Coastguard Worker self.writeline('%s = undefined(%r %% ' 993*635a8641SAndroid Build Coastguard Worker 'included_template.__name__, ' 994*635a8641SAndroid Build Coastguard Worker 'name=%r)' % 995*635a8641SAndroid Build Coastguard Worker (frame.symbols.ref(alias), 996*635a8641SAndroid Build Coastguard Worker 'the template %%r (imported on %s) does ' 997*635a8641SAndroid Build Coastguard Worker 'not export the requested name %s' % ( 998*635a8641SAndroid Build Coastguard Worker self.position(node), 999*635a8641SAndroid Build Coastguard Worker repr(name) 1000*635a8641SAndroid Build Coastguard Worker ), name)) 1001*635a8641SAndroid Build Coastguard Worker self.outdent() 1002*635a8641SAndroid Build Coastguard Worker if frame.toplevel: 1003*635a8641SAndroid Build Coastguard Worker var_names.append(alias) 1004*635a8641SAndroid Build Coastguard Worker if not alias.startswith('_'): 1005*635a8641SAndroid Build Coastguard Worker discarded_names.append(alias) 1006*635a8641SAndroid Build Coastguard Worker 1007*635a8641SAndroid Build Coastguard Worker if var_names: 1008*635a8641SAndroid Build Coastguard Worker if len(var_names) == 1: 1009*635a8641SAndroid Build Coastguard Worker name = var_names[0] 1010*635a8641SAndroid Build Coastguard Worker self.writeline('context.vars[%r] = %s' % 1011*635a8641SAndroid Build Coastguard Worker (name, frame.symbols.ref(name))) 1012*635a8641SAndroid Build Coastguard Worker else: 1013*635a8641SAndroid Build Coastguard Worker self.writeline('context.vars.update({%s})' % ', '.join( 1014*635a8641SAndroid Build Coastguard Worker '%r: %s' % (name, frame.symbols.ref(name)) for name in var_names 1015*635a8641SAndroid Build Coastguard Worker )) 1016*635a8641SAndroid Build Coastguard Worker if discarded_names: 1017*635a8641SAndroid Build Coastguard Worker if len(discarded_names) == 1: 1018*635a8641SAndroid Build Coastguard Worker self.writeline('context.exported_vars.discard(%r)' % 1019*635a8641SAndroid Build Coastguard Worker discarded_names[0]) 1020*635a8641SAndroid Build Coastguard Worker else: 1021*635a8641SAndroid Build Coastguard Worker self.writeline('context.exported_vars.difference_' 1022*635a8641SAndroid Build Coastguard Worker 'update((%s))' % ', '.join(imap(repr, discarded_names))) 1023*635a8641SAndroid Build Coastguard Worker 1024*635a8641SAndroid Build Coastguard Worker def visit_For(self, node, frame): 1025*635a8641SAndroid Build Coastguard Worker loop_frame = frame.inner() 1026*635a8641SAndroid Build Coastguard Worker test_frame = frame.inner() 1027*635a8641SAndroid Build Coastguard Worker else_frame = frame.inner() 1028*635a8641SAndroid Build Coastguard Worker 1029*635a8641SAndroid Build Coastguard Worker # try to figure out if we have an extended loop. An extended loop 1030*635a8641SAndroid Build Coastguard Worker # is necessary if the loop is in recursive mode if the special loop 1031*635a8641SAndroid Build Coastguard Worker # variable is accessed in the body. 1032*635a8641SAndroid Build Coastguard Worker extended_loop = node.recursive or 'loop' in \ 1033*635a8641SAndroid Build Coastguard Worker find_undeclared(node.iter_child_nodes( 1034*635a8641SAndroid Build Coastguard Worker only=('body',)), ('loop',)) 1035*635a8641SAndroid Build Coastguard Worker 1036*635a8641SAndroid Build Coastguard Worker loop_ref = None 1037*635a8641SAndroid Build Coastguard Worker if extended_loop: 1038*635a8641SAndroid Build Coastguard Worker loop_ref = loop_frame.symbols.declare_parameter('loop') 1039*635a8641SAndroid Build Coastguard Worker 1040*635a8641SAndroid Build Coastguard Worker loop_frame.symbols.analyze_node(node, for_branch='body') 1041*635a8641SAndroid Build Coastguard Worker if node.else_: 1042*635a8641SAndroid Build Coastguard Worker else_frame.symbols.analyze_node(node, for_branch='else') 1043*635a8641SAndroid Build Coastguard Worker 1044*635a8641SAndroid Build Coastguard Worker if node.test: 1045*635a8641SAndroid Build Coastguard Worker loop_filter_func = self.temporary_identifier() 1046*635a8641SAndroid Build Coastguard Worker test_frame.symbols.analyze_node(node, for_branch='test') 1047*635a8641SAndroid Build Coastguard Worker self.writeline('%s(fiter):' % self.func(loop_filter_func), node.test) 1048*635a8641SAndroid Build Coastguard Worker self.indent() 1049*635a8641SAndroid Build Coastguard Worker self.enter_frame(test_frame) 1050*635a8641SAndroid Build Coastguard Worker self.writeline(self.environment.is_async and 'async for ' or 'for ') 1051*635a8641SAndroid Build Coastguard Worker self.visit(node.target, loop_frame) 1052*635a8641SAndroid Build Coastguard Worker self.write(' in ') 1053*635a8641SAndroid Build Coastguard Worker self.write(self.environment.is_async and 'auto_aiter(fiter)' or 'fiter') 1054*635a8641SAndroid Build Coastguard Worker self.write(':') 1055*635a8641SAndroid Build Coastguard Worker self.indent() 1056*635a8641SAndroid Build Coastguard Worker self.writeline('if ', node.test) 1057*635a8641SAndroid Build Coastguard Worker self.visit(node.test, test_frame) 1058*635a8641SAndroid Build Coastguard Worker self.write(':') 1059*635a8641SAndroid Build Coastguard Worker self.indent() 1060*635a8641SAndroid Build Coastguard Worker self.writeline('yield ') 1061*635a8641SAndroid Build Coastguard Worker self.visit(node.target, loop_frame) 1062*635a8641SAndroid Build Coastguard Worker self.outdent(3) 1063*635a8641SAndroid Build Coastguard Worker self.leave_frame(test_frame, with_python_scope=True) 1064*635a8641SAndroid Build Coastguard Worker 1065*635a8641SAndroid Build Coastguard Worker # if we don't have an recursive loop we have to find the shadowed 1066*635a8641SAndroid Build Coastguard Worker # variables at that point. Because loops can be nested but the loop 1067*635a8641SAndroid Build Coastguard Worker # variable is a special one we have to enforce aliasing for it. 1068*635a8641SAndroid Build Coastguard Worker if node.recursive: 1069*635a8641SAndroid Build Coastguard Worker self.writeline('%s(reciter, loop_render_func, depth=0):' % 1070*635a8641SAndroid Build Coastguard Worker self.func('loop'), node) 1071*635a8641SAndroid Build Coastguard Worker self.indent() 1072*635a8641SAndroid Build Coastguard Worker self.buffer(loop_frame) 1073*635a8641SAndroid Build Coastguard Worker 1074*635a8641SAndroid Build Coastguard Worker # Use the same buffer for the else frame 1075*635a8641SAndroid Build Coastguard Worker else_frame.buffer = loop_frame.buffer 1076*635a8641SAndroid Build Coastguard Worker 1077*635a8641SAndroid Build Coastguard Worker # make sure the loop variable is a special one and raise a template 1078*635a8641SAndroid Build Coastguard Worker # assertion error if a loop tries to write to loop 1079*635a8641SAndroid Build Coastguard Worker if extended_loop: 1080*635a8641SAndroid Build Coastguard Worker self.writeline('%s = missing' % loop_ref) 1081*635a8641SAndroid Build Coastguard Worker 1082*635a8641SAndroid Build Coastguard Worker for name in node.find_all(nodes.Name): 1083*635a8641SAndroid Build Coastguard Worker if name.ctx == 'store' and name.name == 'loop': 1084*635a8641SAndroid Build Coastguard Worker self.fail('Can\'t assign to special loop variable ' 1085*635a8641SAndroid Build Coastguard Worker 'in for-loop target', name.lineno) 1086*635a8641SAndroid Build Coastguard Worker 1087*635a8641SAndroid Build Coastguard Worker if node.else_: 1088*635a8641SAndroid Build Coastguard Worker iteration_indicator = self.temporary_identifier() 1089*635a8641SAndroid Build Coastguard Worker self.writeline('%s = 1' % iteration_indicator) 1090*635a8641SAndroid Build Coastguard Worker 1091*635a8641SAndroid Build Coastguard Worker self.writeline(self.environment.is_async and 'async for ' or 'for ', node) 1092*635a8641SAndroid Build Coastguard Worker self.visit(node.target, loop_frame) 1093*635a8641SAndroid Build Coastguard Worker if extended_loop: 1094*635a8641SAndroid Build Coastguard Worker if self.environment.is_async: 1095*635a8641SAndroid Build Coastguard Worker self.write(', %s in await make_async_loop_context(' % loop_ref) 1096*635a8641SAndroid Build Coastguard Worker else: 1097*635a8641SAndroid Build Coastguard Worker self.write(', %s in LoopContext(' % loop_ref) 1098*635a8641SAndroid Build Coastguard Worker else: 1099*635a8641SAndroid Build Coastguard Worker self.write(' in ') 1100*635a8641SAndroid Build Coastguard Worker 1101*635a8641SAndroid Build Coastguard Worker if node.test: 1102*635a8641SAndroid Build Coastguard Worker self.write('%s(' % loop_filter_func) 1103*635a8641SAndroid Build Coastguard Worker if node.recursive: 1104*635a8641SAndroid Build Coastguard Worker self.write('reciter') 1105*635a8641SAndroid Build Coastguard Worker else: 1106*635a8641SAndroid Build Coastguard Worker if self.environment.is_async and not extended_loop: 1107*635a8641SAndroid Build Coastguard Worker self.write('auto_aiter(') 1108*635a8641SAndroid Build Coastguard Worker self.visit(node.iter, frame) 1109*635a8641SAndroid Build Coastguard Worker if self.environment.is_async and not extended_loop: 1110*635a8641SAndroid Build Coastguard Worker self.write(')') 1111*635a8641SAndroid Build Coastguard Worker if node.test: 1112*635a8641SAndroid Build Coastguard Worker self.write(')') 1113*635a8641SAndroid Build Coastguard Worker 1114*635a8641SAndroid Build Coastguard Worker if node.recursive: 1115*635a8641SAndroid Build Coastguard Worker self.write(', undefined, loop_render_func, depth):') 1116*635a8641SAndroid Build Coastguard Worker else: 1117*635a8641SAndroid Build Coastguard Worker self.write(extended_loop and ', undefined):' or ':') 1118*635a8641SAndroid Build Coastguard Worker 1119*635a8641SAndroid Build Coastguard Worker self.indent() 1120*635a8641SAndroid Build Coastguard Worker self.enter_frame(loop_frame) 1121*635a8641SAndroid Build Coastguard Worker 1122*635a8641SAndroid Build Coastguard Worker self.blockvisit(node.body, loop_frame) 1123*635a8641SAndroid Build Coastguard Worker if node.else_: 1124*635a8641SAndroid Build Coastguard Worker self.writeline('%s = 0' % iteration_indicator) 1125*635a8641SAndroid Build Coastguard Worker self.outdent() 1126*635a8641SAndroid Build Coastguard Worker self.leave_frame(loop_frame, with_python_scope=node.recursive 1127*635a8641SAndroid Build Coastguard Worker and not node.else_) 1128*635a8641SAndroid Build Coastguard Worker 1129*635a8641SAndroid Build Coastguard Worker if node.else_: 1130*635a8641SAndroid Build Coastguard Worker self.writeline('if %s:' % iteration_indicator) 1131*635a8641SAndroid Build Coastguard Worker self.indent() 1132*635a8641SAndroid Build Coastguard Worker self.enter_frame(else_frame) 1133*635a8641SAndroid Build Coastguard Worker self.blockvisit(node.else_, else_frame) 1134*635a8641SAndroid Build Coastguard Worker self.leave_frame(else_frame) 1135*635a8641SAndroid Build Coastguard Worker self.outdent() 1136*635a8641SAndroid Build Coastguard Worker 1137*635a8641SAndroid Build Coastguard Worker # if the node was recursive we have to return the buffer contents 1138*635a8641SAndroid Build Coastguard Worker # and start the iteration code 1139*635a8641SAndroid Build Coastguard Worker if node.recursive: 1140*635a8641SAndroid Build Coastguard Worker self.return_buffer_contents(loop_frame) 1141*635a8641SAndroid Build Coastguard Worker self.outdent() 1142*635a8641SAndroid Build Coastguard Worker self.start_write(frame, node) 1143*635a8641SAndroid Build Coastguard Worker if self.environment.is_async: 1144*635a8641SAndroid Build Coastguard Worker self.write('await ') 1145*635a8641SAndroid Build Coastguard Worker self.write('loop(') 1146*635a8641SAndroid Build Coastguard Worker if self.environment.is_async: 1147*635a8641SAndroid Build Coastguard Worker self.write('auto_aiter(') 1148*635a8641SAndroid Build Coastguard Worker self.visit(node.iter, frame) 1149*635a8641SAndroid Build Coastguard Worker if self.environment.is_async: 1150*635a8641SAndroid Build Coastguard Worker self.write(')') 1151*635a8641SAndroid Build Coastguard Worker self.write(', loop)') 1152*635a8641SAndroid Build Coastguard Worker self.end_write(frame) 1153*635a8641SAndroid Build Coastguard Worker 1154*635a8641SAndroid Build Coastguard Worker def visit_If(self, node, frame): 1155*635a8641SAndroid Build Coastguard Worker if_frame = frame.soft() 1156*635a8641SAndroid Build Coastguard Worker self.writeline('if ', node) 1157*635a8641SAndroid Build Coastguard Worker self.visit(node.test, if_frame) 1158*635a8641SAndroid Build Coastguard Worker self.write(':') 1159*635a8641SAndroid Build Coastguard Worker self.indent() 1160*635a8641SAndroid Build Coastguard Worker self.blockvisit(node.body, if_frame) 1161*635a8641SAndroid Build Coastguard Worker self.outdent() 1162*635a8641SAndroid Build Coastguard Worker for elif_ in node.elif_: 1163*635a8641SAndroid Build Coastguard Worker self.writeline('elif ', elif_) 1164*635a8641SAndroid Build Coastguard Worker self.visit(elif_.test, if_frame) 1165*635a8641SAndroid Build Coastguard Worker self.write(':') 1166*635a8641SAndroid Build Coastguard Worker self.indent() 1167*635a8641SAndroid Build Coastguard Worker self.blockvisit(elif_.body, if_frame) 1168*635a8641SAndroid Build Coastguard Worker self.outdent() 1169*635a8641SAndroid Build Coastguard Worker if node.else_: 1170*635a8641SAndroid Build Coastguard Worker self.writeline('else:') 1171*635a8641SAndroid Build Coastguard Worker self.indent() 1172*635a8641SAndroid Build Coastguard Worker self.blockvisit(node.else_, if_frame) 1173*635a8641SAndroid Build Coastguard Worker self.outdent() 1174*635a8641SAndroid Build Coastguard Worker 1175*635a8641SAndroid Build Coastguard Worker def visit_Macro(self, node, frame): 1176*635a8641SAndroid Build Coastguard Worker macro_frame, macro_ref = self.macro_body(node, frame) 1177*635a8641SAndroid Build Coastguard Worker self.newline() 1178*635a8641SAndroid Build Coastguard Worker if frame.toplevel: 1179*635a8641SAndroid Build Coastguard Worker if not node.name.startswith('_'): 1180*635a8641SAndroid Build Coastguard Worker self.write('context.exported_vars.add(%r)' % node.name) 1181*635a8641SAndroid Build Coastguard Worker ref = frame.symbols.ref(node.name) 1182*635a8641SAndroid Build Coastguard Worker self.writeline('context.vars[%r] = ' % node.name) 1183*635a8641SAndroid Build Coastguard Worker self.write('%s = ' % frame.symbols.ref(node.name)) 1184*635a8641SAndroid Build Coastguard Worker self.macro_def(macro_ref, macro_frame) 1185*635a8641SAndroid Build Coastguard Worker 1186*635a8641SAndroid Build Coastguard Worker def visit_CallBlock(self, node, frame): 1187*635a8641SAndroid Build Coastguard Worker call_frame, macro_ref = self.macro_body(node, frame) 1188*635a8641SAndroid Build Coastguard Worker self.writeline('caller = ') 1189*635a8641SAndroid Build Coastguard Worker self.macro_def(macro_ref, call_frame) 1190*635a8641SAndroid Build Coastguard Worker self.start_write(frame, node) 1191*635a8641SAndroid Build Coastguard Worker self.visit_Call(node.call, frame, forward_caller=True) 1192*635a8641SAndroid Build Coastguard Worker self.end_write(frame) 1193*635a8641SAndroid Build Coastguard Worker 1194*635a8641SAndroid Build Coastguard Worker def visit_FilterBlock(self, node, frame): 1195*635a8641SAndroid Build Coastguard Worker filter_frame = frame.inner() 1196*635a8641SAndroid Build Coastguard Worker filter_frame.symbols.analyze_node(node) 1197*635a8641SAndroid Build Coastguard Worker self.enter_frame(filter_frame) 1198*635a8641SAndroid Build Coastguard Worker self.buffer(filter_frame) 1199*635a8641SAndroid Build Coastguard Worker self.blockvisit(node.body, filter_frame) 1200*635a8641SAndroid Build Coastguard Worker self.start_write(frame, node) 1201*635a8641SAndroid Build Coastguard Worker self.visit_Filter(node.filter, filter_frame) 1202*635a8641SAndroid Build Coastguard Worker self.end_write(frame) 1203*635a8641SAndroid Build Coastguard Worker self.leave_frame(filter_frame) 1204*635a8641SAndroid Build Coastguard Worker 1205*635a8641SAndroid Build Coastguard Worker def visit_With(self, node, frame): 1206*635a8641SAndroid Build Coastguard Worker with_frame = frame.inner() 1207*635a8641SAndroid Build Coastguard Worker with_frame.symbols.analyze_node(node) 1208*635a8641SAndroid Build Coastguard Worker self.enter_frame(with_frame) 1209*635a8641SAndroid Build Coastguard Worker for idx, (target, expr) in enumerate(izip(node.targets, node.values)): 1210*635a8641SAndroid Build Coastguard Worker self.newline() 1211*635a8641SAndroid Build Coastguard Worker self.visit(target, with_frame) 1212*635a8641SAndroid Build Coastguard Worker self.write(' = ') 1213*635a8641SAndroid Build Coastguard Worker self.visit(expr, frame) 1214*635a8641SAndroid Build Coastguard Worker self.blockvisit(node.body, with_frame) 1215*635a8641SAndroid Build Coastguard Worker self.leave_frame(with_frame) 1216*635a8641SAndroid Build Coastguard Worker 1217*635a8641SAndroid Build Coastguard Worker def visit_ExprStmt(self, node, frame): 1218*635a8641SAndroid Build Coastguard Worker self.newline(node) 1219*635a8641SAndroid Build Coastguard Worker self.visit(node.node, frame) 1220*635a8641SAndroid Build Coastguard Worker 1221*635a8641SAndroid Build Coastguard Worker def visit_Output(self, node, frame): 1222*635a8641SAndroid Build Coastguard Worker # if we have a known extends statement, we don't output anything 1223*635a8641SAndroid Build Coastguard Worker # if we are in a require_output_check section 1224*635a8641SAndroid Build Coastguard Worker if self.has_known_extends and frame.require_output_check: 1225*635a8641SAndroid Build Coastguard Worker return 1226*635a8641SAndroid Build Coastguard Worker 1227*635a8641SAndroid Build Coastguard Worker allow_constant_finalize = True 1228*635a8641SAndroid Build Coastguard Worker if self.environment.finalize: 1229*635a8641SAndroid Build Coastguard Worker func = self.environment.finalize 1230*635a8641SAndroid Build Coastguard Worker if getattr(func, 'contextfunction', False) or \ 1231*635a8641SAndroid Build Coastguard Worker getattr(func, 'evalcontextfunction', False): 1232*635a8641SAndroid Build Coastguard Worker allow_constant_finalize = False 1233*635a8641SAndroid Build Coastguard Worker elif getattr(func, 'environmentfunction', False): 1234*635a8641SAndroid Build Coastguard Worker finalize = lambda x: text_type( 1235*635a8641SAndroid Build Coastguard Worker self.environment.finalize(self.environment, x)) 1236*635a8641SAndroid Build Coastguard Worker else: 1237*635a8641SAndroid Build Coastguard Worker finalize = lambda x: text_type(self.environment.finalize(x)) 1238*635a8641SAndroid Build Coastguard Worker else: 1239*635a8641SAndroid Build Coastguard Worker finalize = text_type 1240*635a8641SAndroid Build Coastguard Worker 1241*635a8641SAndroid Build Coastguard Worker # if we are inside a frame that requires output checking, we do so 1242*635a8641SAndroid Build Coastguard Worker outdent_later = False 1243*635a8641SAndroid Build Coastguard Worker if frame.require_output_check: 1244*635a8641SAndroid Build Coastguard Worker self.writeline('if parent_template is None:') 1245*635a8641SAndroid Build Coastguard Worker self.indent() 1246*635a8641SAndroid Build Coastguard Worker outdent_later = True 1247*635a8641SAndroid Build Coastguard Worker 1248*635a8641SAndroid Build Coastguard Worker # try to evaluate as many chunks as possible into a static 1249*635a8641SAndroid Build Coastguard Worker # string at compile time. 1250*635a8641SAndroid Build Coastguard Worker body = [] 1251*635a8641SAndroid Build Coastguard Worker for child in node.nodes: 1252*635a8641SAndroid Build Coastguard Worker try: 1253*635a8641SAndroid Build Coastguard Worker if not allow_constant_finalize: 1254*635a8641SAndroid Build Coastguard Worker raise nodes.Impossible() 1255*635a8641SAndroid Build Coastguard Worker const = child.as_const(frame.eval_ctx) 1256*635a8641SAndroid Build Coastguard Worker except nodes.Impossible: 1257*635a8641SAndroid Build Coastguard Worker body.append(child) 1258*635a8641SAndroid Build Coastguard Worker continue 1259*635a8641SAndroid Build Coastguard Worker # the frame can't be volatile here, becaus otherwise the 1260*635a8641SAndroid Build Coastguard Worker # as_const() function would raise an Impossible exception 1261*635a8641SAndroid Build Coastguard Worker # at that point. 1262*635a8641SAndroid Build Coastguard Worker try: 1263*635a8641SAndroid Build Coastguard Worker if frame.eval_ctx.autoescape: 1264*635a8641SAndroid Build Coastguard Worker if hasattr(const, '__html__'): 1265*635a8641SAndroid Build Coastguard Worker const = const.__html__() 1266*635a8641SAndroid Build Coastguard Worker else: 1267*635a8641SAndroid Build Coastguard Worker const = escape(const) 1268*635a8641SAndroid Build Coastguard Worker const = finalize(const) 1269*635a8641SAndroid Build Coastguard Worker except Exception: 1270*635a8641SAndroid Build Coastguard Worker # if something goes wrong here we evaluate the node 1271*635a8641SAndroid Build Coastguard Worker # at runtime for easier debugging 1272*635a8641SAndroid Build Coastguard Worker body.append(child) 1273*635a8641SAndroid Build Coastguard Worker continue 1274*635a8641SAndroid Build Coastguard Worker if body and isinstance(body[-1], list): 1275*635a8641SAndroid Build Coastguard Worker body[-1].append(const) 1276*635a8641SAndroid Build Coastguard Worker else: 1277*635a8641SAndroid Build Coastguard Worker body.append([const]) 1278*635a8641SAndroid Build Coastguard Worker 1279*635a8641SAndroid Build Coastguard Worker # if we have less than 3 nodes or a buffer we yield or extend/append 1280*635a8641SAndroid Build Coastguard Worker if len(body) < 3 or frame.buffer is not None: 1281*635a8641SAndroid Build Coastguard Worker if frame.buffer is not None: 1282*635a8641SAndroid Build Coastguard Worker # for one item we append, for more we extend 1283*635a8641SAndroid Build Coastguard Worker if len(body) == 1: 1284*635a8641SAndroid Build Coastguard Worker self.writeline('%s.append(' % frame.buffer) 1285*635a8641SAndroid Build Coastguard Worker else: 1286*635a8641SAndroid Build Coastguard Worker self.writeline('%s.extend((' % frame.buffer) 1287*635a8641SAndroid Build Coastguard Worker self.indent() 1288*635a8641SAndroid Build Coastguard Worker for item in body: 1289*635a8641SAndroid Build Coastguard Worker if isinstance(item, list): 1290*635a8641SAndroid Build Coastguard Worker val = repr(concat(item)) 1291*635a8641SAndroid Build Coastguard Worker if frame.buffer is None: 1292*635a8641SAndroid Build Coastguard Worker self.writeline('yield ' + val) 1293*635a8641SAndroid Build Coastguard Worker else: 1294*635a8641SAndroid Build Coastguard Worker self.writeline(val + ',') 1295*635a8641SAndroid Build Coastguard Worker else: 1296*635a8641SAndroid Build Coastguard Worker if frame.buffer is None: 1297*635a8641SAndroid Build Coastguard Worker self.writeline('yield ', item) 1298*635a8641SAndroid Build Coastguard Worker else: 1299*635a8641SAndroid Build Coastguard Worker self.newline(item) 1300*635a8641SAndroid Build Coastguard Worker close = 1 1301*635a8641SAndroid Build Coastguard Worker if frame.eval_ctx.volatile: 1302*635a8641SAndroid Build Coastguard Worker self.write('(escape if context.eval_ctx.autoescape' 1303*635a8641SAndroid Build Coastguard Worker ' else to_string)(') 1304*635a8641SAndroid Build Coastguard Worker elif frame.eval_ctx.autoescape: 1305*635a8641SAndroid Build Coastguard Worker self.write('escape(') 1306*635a8641SAndroid Build Coastguard Worker else: 1307*635a8641SAndroid Build Coastguard Worker self.write('to_string(') 1308*635a8641SAndroid Build Coastguard Worker if self.environment.finalize is not None: 1309*635a8641SAndroid Build Coastguard Worker self.write('environment.finalize(') 1310*635a8641SAndroid Build Coastguard Worker if getattr(self.environment.finalize, 1311*635a8641SAndroid Build Coastguard Worker "contextfunction", False): 1312*635a8641SAndroid Build Coastguard Worker self.write('context, ') 1313*635a8641SAndroid Build Coastguard Worker close += 1 1314*635a8641SAndroid Build Coastguard Worker self.visit(item, frame) 1315*635a8641SAndroid Build Coastguard Worker self.write(')' * close) 1316*635a8641SAndroid Build Coastguard Worker if frame.buffer is not None: 1317*635a8641SAndroid Build Coastguard Worker self.write(',') 1318*635a8641SAndroid Build Coastguard Worker if frame.buffer is not None: 1319*635a8641SAndroid Build Coastguard Worker # close the open parentheses 1320*635a8641SAndroid Build Coastguard Worker self.outdent() 1321*635a8641SAndroid Build Coastguard Worker self.writeline(len(body) == 1 and ')' or '))') 1322*635a8641SAndroid Build Coastguard Worker 1323*635a8641SAndroid Build Coastguard Worker # otherwise we create a format string as this is faster in that case 1324*635a8641SAndroid Build Coastguard Worker else: 1325*635a8641SAndroid Build Coastguard Worker format = [] 1326*635a8641SAndroid Build Coastguard Worker arguments = [] 1327*635a8641SAndroid Build Coastguard Worker for item in body: 1328*635a8641SAndroid Build Coastguard Worker if isinstance(item, list): 1329*635a8641SAndroid Build Coastguard Worker format.append(concat(item).replace('%', '%%')) 1330*635a8641SAndroid Build Coastguard Worker else: 1331*635a8641SAndroid Build Coastguard Worker format.append('%s') 1332*635a8641SAndroid Build Coastguard Worker arguments.append(item) 1333*635a8641SAndroid Build Coastguard Worker self.writeline('yield ') 1334*635a8641SAndroid Build Coastguard Worker self.write(repr(concat(format)) + ' % (') 1335*635a8641SAndroid Build Coastguard Worker self.indent() 1336*635a8641SAndroid Build Coastguard Worker for argument in arguments: 1337*635a8641SAndroid Build Coastguard Worker self.newline(argument) 1338*635a8641SAndroid Build Coastguard Worker close = 0 1339*635a8641SAndroid Build Coastguard Worker if frame.eval_ctx.volatile: 1340*635a8641SAndroid Build Coastguard Worker self.write('(escape if context.eval_ctx.autoescape else' 1341*635a8641SAndroid Build Coastguard Worker ' to_string)(') 1342*635a8641SAndroid Build Coastguard Worker close += 1 1343*635a8641SAndroid Build Coastguard Worker elif frame.eval_ctx.autoescape: 1344*635a8641SAndroid Build Coastguard Worker self.write('escape(') 1345*635a8641SAndroid Build Coastguard Worker close += 1 1346*635a8641SAndroid Build Coastguard Worker if self.environment.finalize is not None: 1347*635a8641SAndroid Build Coastguard Worker self.write('environment.finalize(') 1348*635a8641SAndroid Build Coastguard Worker if getattr(self.environment.finalize, 1349*635a8641SAndroid Build Coastguard Worker 'contextfunction', False): 1350*635a8641SAndroid Build Coastguard Worker self.write('context, ') 1351*635a8641SAndroid Build Coastguard Worker elif getattr(self.environment.finalize, 1352*635a8641SAndroid Build Coastguard Worker 'evalcontextfunction', False): 1353*635a8641SAndroid Build Coastguard Worker self.write('context.eval_ctx, ') 1354*635a8641SAndroid Build Coastguard Worker elif getattr(self.environment.finalize, 1355*635a8641SAndroid Build Coastguard Worker 'environmentfunction', False): 1356*635a8641SAndroid Build Coastguard Worker self.write('environment, ') 1357*635a8641SAndroid Build Coastguard Worker close += 1 1358*635a8641SAndroid Build Coastguard Worker self.visit(argument, frame) 1359*635a8641SAndroid Build Coastguard Worker self.write(')' * close + ', ') 1360*635a8641SAndroid Build Coastguard Worker self.outdent() 1361*635a8641SAndroid Build Coastguard Worker self.writeline(')') 1362*635a8641SAndroid Build Coastguard Worker 1363*635a8641SAndroid Build Coastguard Worker if outdent_later: 1364*635a8641SAndroid Build Coastguard Worker self.outdent() 1365*635a8641SAndroid Build Coastguard Worker 1366*635a8641SAndroid Build Coastguard Worker def visit_Assign(self, node, frame): 1367*635a8641SAndroid Build Coastguard Worker self.push_assign_tracking() 1368*635a8641SAndroid Build Coastguard Worker self.newline(node) 1369*635a8641SAndroid Build Coastguard Worker self.visit(node.target, frame) 1370*635a8641SAndroid Build Coastguard Worker self.write(' = ') 1371*635a8641SAndroid Build Coastguard Worker self.visit(node.node, frame) 1372*635a8641SAndroid Build Coastguard Worker self.pop_assign_tracking(frame) 1373*635a8641SAndroid Build Coastguard Worker 1374*635a8641SAndroid Build Coastguard Worker def visit_AssignBlock(self, node, frame): 1375*635a8641SAndroid Build Coastguard Worker self.push_assign_tracking() 1376*635a8641SAndroid Build Coastguard Worker block_frame = frame.inner() 1377*635a8641SAndroid Build Coastguard Worker # This is a special case. Since a set block always captures we 1378*635a8641SAndroid Build Coastguard Worker # will disable output checks. This way one can use set blocks 1379*635a8641SAndroid Build Coastguard Worker # toplevel even in extended templates. 1380*635a8641SAndroid Build Coastguard Worker block_frame.require_output_check = False 1381*635a8641SAndroid Build Coastguard Worker block_frame.symbols.analyze_node(node) 1382*635a8641SAndroid Build Coastguard Worker self.enter_frame(block_frame) 1383*635a8641SAndroid Build Coastguard Worker self.buffer(block_frame) 1384*635a8641SAndroid Build Coastguard Worker self.blockvisit(node.body, block_frame) 1385*635a8641SAndroid Build Coastguard Worker self.newline(node) 1386*635a8641SAndroid Build Coastguard Worker self.visit(node.target, frame) 1387*635a8641SAndroid Build Coastguard Worker self.write(' = (Markup if context.eval_ctx.autoescape ' 1388*635a8641SAndroid Build Coastguard Worker 'else identity)(') 1389*635a8641SAndroid Build Coastguard Worker if node.filter is not None: 1390*635a8641SAndroid Build Coastguard Worker self.visit_Filter(node.filter, block_frame) 1391*635a8641SAndroid Build Coastguard Worker else: 1392*635a8641SAndroid Build Coastguard Worker self.write('concat(%s)' % block_frame.buffer) 1393*635a8641SAndroid Build Coastguard Worker self.write(')') 1394*635a8641SAndroid Build Coastguard Worker self.pop_assign_tracking(frame) 1395*635a8641SAndroid Build Coastguard Worker self.leave_frame(block_frame) 1396*635a8641SAndroid Build Coastguard Worker 1397*635a8641SAndroid Build Coastguard Worker # -- Expression Visitors 1398*635a8641SAndroid Build Coastguard Worker 1399*635a8641SAndroid Build Coastguard Worker def visit_Name(self, node, frame): 1400*635a8641SAndroid Build Coastguard Worker if node.ctx == 'store' and frame.toplevel: 1401*635a8641SAndroid Build Coastguard Worker if self._assign_stack: 1402*635a8641SAndroid Build Coastguard Worker self._assign_stack[-1].add(node.name) 1403*635a8641SAndroid Build Coastguard Worker ref = frame.symbols.ref(node.name) 1404*635a8641SAndroid Build Coastguard Worker 1405*635a8641SAndroid Build Coastguard Worker # If we are looking up a variable we might have to deal with the 1406*635a8641SAndroid Build Coastguard Worker # case where it's undefined. We can skip that case if the load 1407*635a8641SAndroid Build Coastguard Worker # instruction indicates a parameter which are always defined. 1408*635a8641SAndroid Build Coastguard Worker if node.ctx == 'load': 1409*635a8641SAndroid Build Coastguard Worker load = frame.symbols.find_load(ref) 1410*635a8641SAndroid Build Coastguard Worker if not (load is not None and load[0] == VAR_LOAD_PARAMETER and \ 1411*635a8641SAndroid Build Coastguard Worker not self.parameter_is_undeclared(ref)): 1412*635a8641SAndroid Build Coastguard Worker self.write('(undefined(name=%r) if %s is missing else %s)' % 1413*635a8641SAndroid Build Coastguard Worker (node.name, ref, ref)) 1414*635a8641SAndroid Build Coastguard Worker return 1415*635a8641SAndroid Build Coastguard Worker 1416*635a8641SAndroid Build Coastguard Worker self.write(ref) 1417*635a8641SAndroid Build Coastguard Worker 1418*635a8641SAndroid Build Coastguard Worker def visit_NSRef(self, node, frame): 1419*635a8641SAndroid Build Coastguard Worker # NSRefs can only be used to store values; since they use the normal 1420*635a8641SAndroid Build Coastguard Worker # `foo.bar` notation they will be parsed as a normal attribute access 1421*635a8641SAndroid Build Coastguard Worker # when used anywhere but in a `set` context 1422*635a8641SAndroid Build Coastguard Worker ref = frame.symbols.ref(node.name) 1423*635a8641SAndroid Build Coastguard Worker self.writeline('if not isinstance(%s, Namespace):' % ref) 1424*635a8641SAndroid Build Coastguard Worker self.indent() 1425*635a8641SAndroid Build Coastguard Worker self.writeline('raise TemplateRuntimeError(%r)' % 1426*635a8641SAndroid Build Coastguard Worker 'cannot assign attribute on non-namespace object') 1427*635a8641SAndroid Build Coastguard Worker self.outdent() 1428*635a8641SAndroid Build Coastguard Worker self.writeline('%s[%r]' % (ref, node.attr)) 1429*635a8641SAndroid Build Coastguard Worker 1430*635a8641SAndroid Build Coastguard Worker def visit_Const(self, node, frame): 1431*635a8641SAndroid Build Coastguard Worker val = node.as_const(frame.eval_ctx) 1432*635a8641SAndroid Build Coastguard Worker if isinstance(val, float): 1433*635a8641SAndroid Build Coastguard Worker self.write(str(val)) 1434*635a8641SAndroid Build Coastguard Worker else: 1435*635a8641SAndroid Build Coastguard Worker self.write(repr(val)) 1436*635a8641SAndroid Build Coastguard Worker 1437*635a8641SAndroid Build Coastguard Worker def visit_TemplateData(self, node, frame): 1438*635a8641SAndroid Build Coastguard Worker try: 1439*635a8641SAndroid Build Coastguard Worker self.write(repr(node.as_const(frame.eval_ctx))) 1440*635a8641SAndroid Build Coastguard Worker except nodes.Impossible: 1441*635a8641SAndroid Build Coastguard Worker self.write('(Markup if context.eval_ctx.autoescape else identity)(%r)' 1442*635a8641SAndroid Build Coastguard Worker % node.data) 1443*635a8641SAndroid Build Coastguard Worker 1444*635a8641SAndroid Build Coastguard Worker def visit_Tuple(self, node, frame): 1445*635a8641SAndroid Build Coastguard Worker self.write('(') 1446*635a8641SAndroid Build Coastguard Worker idx = -1 1447*635a8641SAndroid Build Coastguard Worker for idx, item in enumerate(node.items): 1448*635a8641SAndroid Build Coastguard Worker if idx: 1449*635a8641SAndroid Build Coastguard Worker self.write(', ') 1450*635a8641SAndroid Build Coastguard Worker self.visit(item, frame) 1451*635a8641SAndroid Build Coastguard Worker self.write(idx == 0 and ',)' or ')') 1452*635a8641SAndroid Build Coastguard Worker 1453*635a8641SAndroid Build Coastguard Worker def visit_List(self, node, frame): 1454*635a8641SAndroid Build Coastguard Worker self.write('[') 1455*635a8641SAndroid Build Coastguard Worker for idx, item in enumerate(node.items): 1456*635a8641SAndroid Build Coastguard Worker if idx: 1457*635a8641SAndroid Build Coastguard Worker self.write(', ') 1458*635a8641SAndroid Build Coastguard Worker self.visit(item, frame) 1459*635a8641SAndroid Build Coastguard Worker self.write(']') 1460*635a8641SAndroid Build Coastguard Worker 1461*635a8641SAndroid Build Coastguard Worker def visit_Dict(self, node, frame): 1462*635a8641SAndroid Build Coastguard Worker self.write('{') 1463*635a8641SAndroid Build Coastguard Worker for idx, item in enumerate(node.items): 1464*635a8641SAndroid Build Coastguard Worker if idx: 1465*635a8641SAndroid Build Coastguard Worker self.write(', ') 1466*635a8641SAndroid Build Coastguard Worker self.visit(item.key, frame) 1467*635a8641SAndroid Build Coastguard Worker self.write(': ') 1468*635a8641SAndroid Build Coastguard Worker self.visit(item.value, frame) 1469*635a8641SAndroid Build Coastguard Worker self.write('}') 1470*635a8641SAndroid Build Coastguard Worker 1471*635a8641SAndroid Build Coastguard Worker def binop(operator, interceptable=True): 1472*635a8641SAndroid Build Coastguard Worker @optimizeconst 1473*635a8641SAndroid Build Coastguard Worker def visitor(self, node, frame): 1474*635a8641SAndroid Build Coastguard Worker if self.environment.sandboxed and \ 1475*635a8641SAndroid Build Coastguard Worker operator in self.environment.intercepted_binops: 1476*635a8641SAndroid Build Coastguard Worker self.write('environment.call_binop(context, %r, ' % operator) 1477*635a8641SAndroid Build Coastguard Worker self.visit(node.left, frame) 1478*635a8641SAndroid Build Coastguard Worker self.write(', ') 1479*635a8641SAndroid Build Coastguard Worker self.visit(node.right, frame) 1480*635a8641SAndroid Build Coastguard Worker else: 1481*635a8641SAndroid Build Coastguard Worker self.write('(') 1482*635a8641SAndroid Build Coastguard Worker self.visit(node.left, frame) 1483*635a8641SAndroid Build Coastguard Worker self.write(' %s ' % operator) 1484*635a8641SAndroid Build Coastguard Worker self.visit(node.right, frame) 1485*635a8641SAndroid Build Coastguard Worker self.write(')') 1486*635a8641SAndroid Build Coastguard Worker return visitor 1487*635a8641SAndroid Build Coastguard Worker 1488*635a8641SAndroid Build Coastguard Worker def uaop(operator, interceptable=True): 1489*635a8641SAndroid Build Coastguard Worker @optimizeconst 1490*635a8641SAndroid Build Coastguard Worker def visitor(self, node, frame): 1491*635a8641SAndroid Build Coastguard Worker if self.environment.sandboxed and \ 1492*635a8641SAndroid Build Coastguard Worker operator in self.environment.intercepted_unops: 1493*635a8641SAndroid Build Coastguard Worker self.write('environment.call_unop(context, %r, ' % operator) 1494*635a8641SAndroid Build Coastguard Worker self.visit(node.node, frame) 1495*635a8641SAndroid Build Coastguard Worker else: 1496*635a8641SAndroid Build Coastguard Worker self.write('(' + operator) 1497*635a8641SAndroid Build Coastguard Worker self.visit(node.node, frame) 1498*635a8641SAndroid Build Coastguard Worker self.write(')') 1499*635a8641SAndroid Build Coastguard Worker return visitor 1500*635a8641SAndroid Build Coastguard Worker 1501*635a8641SAndroid Build Coastguard Worker visit_Add = binop('+') 1502*635a8641SAndroid Build Coastguard Worker visit_Sub = binop('-') 1503*635a8641SAndroid Build Coastguard Worker visit_Mul = binop('*') 1504*635a8641SAndroid Build Coastguard Worker visit_Div = binop('/') 1505*635a8641SAndroid Build Coastguard Worker visit_FloorDiv = binop('//') 1506*635a8641SAndroid Build Coastguard Worker visit_Pow = binop('**') 1507*635a8641SAndroid Build Coastguard Worker visit_Mod = binop('%') 1508*635a8641SAndroid Build Coastguard Worker visit_And = binop('and', interceptable=False) 1509*635a8641SAndroid Build Coastguard Worker visit_Or = binop('or', interceptable=False) 1510*635a8641SAndroid Build Coastguard Worker visit_Pos = uaop('+') 1511*635a8641SAndroid Build Coastguard Worker visit_Neg = uaop('-') 1512*635a8641SAndroid Build Coastguard Worker visit_Not = uaop('not ', interceptable=False) 1513*635a8641SAndroid Build Coastguard Worker del binop, uaop 1514*635a8641SAndroid Build Coastguard Worker 1515*635a8641SAndroid Build Coastguard Worker @optimizeconst 1516*635a8641SAndroid Build Coastguard Worker def visit_Concat(self, node, frame): 1517*635a8641SAndroid Build Coastguard Worker if frame.eval_ctx.volatile: 1518*635a8641SAndroid Build Coastguard Worker func_name = '(context.eval_ctx.volatile and' \ 1519*635a8641SAndroid Build Coastguard Worker ' markup_join or unicode_join)' 1520*635a8641SAndroid Build Coastguard Worker elif frame.eval_ctx.autoescape: 1521*635a8641SAndroid Build Coastguard Worker func_name = 'markup_join' 1522*635a8641SAndroid Build Coastguard Worker else: 1523*635a8641SAndroid Build Coastguard Worker func_name = 'unicode_join' 1524*635a8641SAndroid Build Coastguard Worker self.write('%s((' % func_name) 1525*635a8641SAndroid Build Coastguard Worker for arg in node.nodes: 1526*635a8641SAndroid Build Coastguard Worker self.visit(arg, frame) 1527*635a8641SAndroid Build Coastguard Worker self.write(', ') 1528*635a8641SAndroid Build Coastguard Worker self.write('))') 1529*635a8641SAndroid Build Coastguard Worker 1530*635a8641SAndroid Build Coastguard Worker @optimizeconst 1531*635a8641SAndroid Build Coastguard Worker def visit_Compare(self, node, frame): 1532*635a8641SAndroid Build Coastguard Worker self.visit(node.expr, frame) 1533*635a8641SAndroid Build Coastguard Worker for op in node.ops: 1534*635a8641SAndroid Build Coastguard Worker self.visit(op, frame) 1535*635a8641SAndroid Build Coastguard Worker 1536*635a8641SAndroid Build Coastguard Worker def visit_Operand(self, node, frame): 1537*635a8641SAndroid Build Coastguard Worker self.write(' %s ' % operators[node.op]) 1538*635a8641SAndroid Build Coastguard Worker self.visit(node.expr, frame) 1539*635a8641SAndroid Build Coastguard Worker 1540*635a8641SAndroid Build Coastguard Worker @optimizeconst 1541*635a8641SAndroid Build Coastguard Worker def visit_Getattr(self, node, frame): 1542*635a8641SAndroid Build Coastguard Worker self.write('environment.getattr(') 1543*635a8641SAndroid Build Coastguard Worker self.visit(node.node, frame) 1544*635a8641SAndroid Build Coastguard Worker self.write(', %r)' % node.attr) 1545*635a8641SAndroid Build Coastguard Worker 1546*635a8641SAndroid Build Coastguard Worker @optimizeconst 1547*635a8641SAndroid Build Coastguard Worker def visit_Getitem(self, node, frame): 1548*635a8641SAndroid Build Coastguard Worker # slices bypass the environment getitem method. 1549*635a8641SAndroid Build Coastguard Worker if isinstance(node.arg, nodes.Slice): 1550*635a8641SAndroid Build Coastguard Worker self.visit(node.node, frame) 1551*635a8641SAndroid Build Coastguard Worker self.write('[') 1552*635a8641SAndroid Build Coastguard Worker self.visit(node.arg, frame) 1553*635a8641SAndroid Build Coastguard Worker self.write(']') 1554*635a8641SAndroid Build Coastguard Worker else: 1555*635a8641SAndroid Build Coastguard Worker self.write('environment.getitem(') 1556*635a8641SAndroid Build Coastguard Worker self.visit(node.node, frame) 1557*635a8641SAndroid Build Coastguard Worker self.write(', ') 1558*635a8641SAndroid Build Coastguard Worker self.visit(node.arg, frame) 1559*635a8641SAndroid Build Coastguard Worker self.write(')') 1560*635a8641SAndroid Build Coastguard Worker 1561*635a8641SAndroid Build Coastguard Worker def visit_Slice(self, node, frame): 1562*635a8641SAndroid Build Coastguard Worker if node.start is not None: 1563*635a8641SAndroid Build Coastguard Worker self.visit(node.start, frame) 1564*635a8641SAndroid Build Coastguard Worker self.write(':') 1565*635a8641SAndroid Build Coastguard Worker if node.stop is not None: 1566*635a8641SAndroid Build Coastguard Worker self.visit(node.stop, frame) 1567*635a8641SAndroid Build Coastguard Worker if node.step is not None: 1568*635a8641SAndroid Build Coastguard Worker self.write(':') 1569*635a8641SAndroid Build Coastguard Worker self.visit(node.step, frame) 1570*635a8641SAndroid Build Coastguard Worker 1571*635a8641SAndroid Build Coastguard Worker @optimizeconst 1572*635a8641SAndroid Build Coastguard Worker def visit_Filter(self, node, frame): 1573*635a8641SAndroid Build Coastguard Worker if self.environment.is_async: 1574*635a8641SAndroid Build Coastguard Worker self.write('await auto_await(') 1575*635a8641SAndroid Build Coastguard Worker self.write(self.filters[node.name] + '(') 1576*635a8641SAndroid Build Coastguard Worker func = self.environment.filters.get(node.name) 1577*635a8641SAndroid Build Coastguard Worker if func is None: 1578*635a8641SAndroid Build Coastguard Worker self.fail('no filter named %r' % node.name, node.lineno) 1579*635a8641SAndroid Build Coastguard Worker if getattr(func, 'contextfilter', False): 1580*635a8641SAndroid Build Coastguard Worker self.write('context, ') 1581*635a8641SAndroid Build Coastguard Worker elif getattr(func, 'evalcontextfilter', False): 1582*635a8641SAndroid Build Coastguard Worker self.write('context.eval_ctx, ') 1583*635a8641SAndroid Build Coastguard Worker elif getattr(func, 'environmentfilter', False): 1584*635a8641SAndroid Build Coastguard Worker self.write('environment, ') 1585*635a8641SAndroid Build Coastguard Worker 1586*635a8641SAndroid Build Coastguard Worker # if the filter node is None we are inside a filter block 1587*635a8641SAndroid Build Coastguard Worker # and want to write to the current buffer 1588*635a8641SAndroid Build Coastguard Worker if node.node is not None: 1589*635a8641SAndroid Build Coastguard Worker self.visit(node.node, frame) 1590*635a8641SAndroid Build Coastguard Worker elif frame.eval_ctx.volatile: 1591*635a8641SAndroid Build Coastguard Worker self.write('(context.eval_ctx.autoescape and' 1592*635a8641SAndroid Build Coastguard Worker ' Markup(concat(%s)) or concat(%s))' % 1593*635a8641SAndroid Build Coastguard Worker (frame.buffer, frame.buffer)) 1594*635a8641SAndroid Build Coastguard Worker elif frame.eval_ctx.autoescape: 1595*635a8641SAndroid Build Coastguard Worker self.write('Markup(concat(%s))' % frame.buffer) 1596*635a8641SAndroid Build Coastguard Worker else: 1597*635a8641SAndroid Build Coastguard Worker self.write('concat(%s)' % frame.buffer) 1598*635a8641SAndroid Build Coastguard Worker self.signature(node, frame) 1599*635a8641SAndroid Build Coastguard Worker self.write(')') 1600*635a8641SAndroid Build Coastguard Worker if self.environment.is_async: 1601*635a8641SAndroid Build Coastguard Worker self.write(')') 1602*635a8641SAndroid Build Coastguard Worker 1603*635a8641SAndroid Build Coastguard Worker @optimizeconst 1604*635a8641SAndroid Build Coastguard Worker def visit_Test(self, node, frame): 1605*635a8641SAndroid Build Coastguard Worker self.write(self.tests[node.name] + '(') 1606*635a8641SAndroid Build Coastguard Worker if node.name not in self.environment.tests: 1607*635a8641SAndroid Build Coastguard Worker self.fail('no test named %r' % node.name, node.lineno) 1608*635a8641SAndroid Build Coastguard Worker self.visit(node.node, frame) 1609*635a8641SAndroid Build Coastguard Worker self.signature(node, frame) 1610*635a8641SAndroid Build Coastguard Worker self.write(')') 1611*635a8641SAndroid Build Coastguard Worker 1612*635a8641SAndroid Build Coastguard Worker @optimizeconst 1613*635a8641SAndroid Build Coastguard Worker def visit_CondExpr(self, node, frame): 1614*635a8641SAndroid Build Coastguard Worker def write_expr2(): 1615*635a8641SAndroid Build Coastguard Worker if node.expr2 is not None: 1616*635a8641SAndroid Build Coastguard Worker return self.visit(node.expr2, frame) 1617*635a8641SAndroid Build Coastguard Worker self.write('undefined(%r)' % ('the inline if-' 1618*635a8641SAndroid Build Coastguard Worker 'expression on %s evaluated to false and ' 1619*635a8641SAndroid Build Coastguard Worker 'no else section was defined.' % self.position(node))) 1620*635a8641SAndroid Build Coastguard Worker 1621*635a8641SAndroid Build Coastguard Worker self.write('(') 1622*635a8641SAndroid Build Coastguard Worker self.visit(node.expr1, frame) 1623*635a8641SAndroid Build Coastguard Worker self.write(' if ') 1624*635a8641SAndroid Build Coastguard Worker self.visit(node.test, frame) 1625*635a8641SAndroid Build Coastguard Worker self.write(' else ') 1626*635a8641SAndroid Build Coastguard Worker write_expr2() 1627*635a8641SAndroid Build Coastguard Worker self.write(')') 1628*635a8641SAndroid Build Coastguard Worker 1629*635a8641SAndroid Build Coastguard Worker @optimizeconst 1630*635a8641SAndroid Build Coastguard Worker def visit_Call(self, node, frame, forward_caller=False): 1631*635a8641SAndroid Build Coastguard Worker if self.environment.is_async: 1632*635a8641SAndroid Build Coastguard Worker self.write('await auto_await(') 1633*635a8641SAndroid Build Coastguard Worker if self.environment.sandboxed: 1634*635a8641SAndroid Build Coastguard Worker self.write('environment.call(context, ') 1635*635a8641SAndroid Build Coastguard Worker else: 1636*635a8641SAndroid Build Coastguard Worker self.write('context.call(') 1637*635a8641SAndroid Build Coastguard Worker self.visit(node.node, frame) 1638*635a8641SAndroid Build Coastguard Worker extra_kwargs = forward_caller and {'caller': 'caller'} or None 1639*635a8641SAndroid Build Coastguard Worker self.signature(node, frame, extra_kwargs) 1640*635a8641SAndroid Build Coastguard Worker self.write(')') 1641*635a8641SAndroid Build Coastguard Worker if self.environment.is_async: 1642*635a8641SAndroid Build Coastguard Worker self.write(')') 1643*635a8641SAndroid Build Coastguard Worker 1644*635a8641SAndroid Build Coastguard Worker def visit_Keyword(self, node, frame): 1645*635a8641SAndroid Build Coastguard Worker self.write(node.key + '=') 1646*635a8641SAndroid Build Coastguard Worker self.visit(node.value, frame) 1647*635a8641SAndroid Build Coastguard Worker 1648*635a8641SAndroid Build Coastguard Worker # -- Unused nodes for extensions 1649*635a8641SAndroid Build Coastguard Worker 1650*635a8641SAndroid Build Coastguard Worker def visit_MarkSafe(self, node, frame): 1651*635a8641SAndroid Build Coastguard Worker self.write('Markup(') 1652*635a8641SAndroid Build Coastguard Worker self.visit(node.expr, frame) 1653*635a8641SAndroid Build Coastguard Worker self.write(')') 1654*635a8641SAndroid Build Coastguard Worker 1655*635a8641SAndroid Build Coastguard Worker def visit_MarkSafeIfAutoescape(self, node, frame): 1656*635a8641SAndroid Build Coastguard Worker self.write('(context.eval_ctx.autoescape and Markup or identity)(') 1657*635a8641SAndroid Build Coastguard Worker self.visit(node.expr, frame) 1658*635a8641SAndroid Build Coastguard Worker self.write(')') 1659*635a8641SAndroid Build Coastguard Worker 1660*635a8641SAndroid Build Coastguard Worker def visit_EnvironmentAttribute(self, node, frame): 1661*635a8641SAndroid Build Coastguard Worker self.write('environment.' + node.name) 1662*635a8641SAndroid Build Coastguard Worker 1663*635a8641SAndroid Build Coastguard Worker def visit_ExtensionAttribute(self, node, frame): 1664*635a8641SAndroid Build Coastguard Worker self.write('environment.extensions[%r].%s' % (node.identifier, node.name)) 1665*635a8641SAndroid Build Coastguard Worker 1666*635a8641SAndroid Build Coastguard Worker def visit_ImportedName(self, node, frame): 1667*635a8641SAndroid Build Coastguard Worker self.write(self.import_aliases[node.importname]) 1668*635a8641SAndroid Build Coastguard Worker 1669*635a8641SAndroid Build Coastguard Worker def visit_InternalName(self, node, frame): 1670*635a8641SAndroid Build Coastguard Worker self.write(node.name) 1671*635a8641SAndroid Build Coastguard Worker 1672*635a8641SAndroid Build Coastguard Worker def visit_ContextReference(self, node, frame): 1673*635a8641SAndroid Build Coastguard Worker self.write('context') 1674*635a8641SAndroid Build Coastguard Worker 1675*635a8641SAndroid Build Coastguard Worker def visit_Continue(self, node, frame): 1676*635a8641SAndroid Build Coastguard Worker self.writeline('continue', node) 1677*635a8641SAndroid Build Coastguard Worker 1678*635a8641SAndroid Build Coastguard Worker def visit_Break(self, node, frame): 1679*635a8641SAndroid Build Coastguard Worker self.writeline('break', node) 1680*635a8641SAndroid Build Coastguard Worker 1681*635a8641SAndroid Build Coastguard Worker def visit_Scope(self, node, frame): 1682*635a8641SAndroid Build Coastguard Worker scope_frame = frame.inner() 1683*635a8641SAndroid Build Coastguard Worker scope_frame.symbols.analyze_node(node) 1684*635a8641SAndroid Build Coastguard Worker self.enter_frame(scope_frame) 1685*635a8641SAndroid Build Coastguard Worker self.blockvisit(node.body, scope_frame) 1686*635a8641SAndroid Build Coastguard Worker self.leave_frame(scope_frame) 1687*635a8641SAndroid Build Coastguard Worker 1688*635a8641SAndroid Build Coastguard Worker def visit_OverlayScope(self, node, frame): 1689*635a8641SAndroid Build Coastguard Worker ctx = self.temporary_identifier() 1690*635a8641SAndroid Build Coastguard Worker self.writeline('%s = %s' % (ctx, self.derive_context(frame))) 1691*635a8641SAndroid Build Coastguard Worker self.writeline('%s.vars = ' % ctx) 1692*635a8641SAndroid Build Coastguard Worker self.visit(node.context, frame) 1693*635a8641SAndroid Build Coastguard Worker self.push_context_reference(ctx) 1694*635a8641SAndroid Build Coastguard Worker 1695*635a8641SAndroid Build Coastguard Worker scope_frame = frame.inner(isolated=True) 1696*635a8641SAndroid Build Coastguard Worker scope_frame.symbols.analyze_node(node) 1697*635a8641SAndroid Build Coastguard Worker self.enter_frame(scope_frame) 1698*635a8641SAndroid Build Coastguard Worker self.blockvisit(node.body, scope_frame) 1699*635a8641SAndroid Build Coastguard Worker self.leave_frame(scope_frame) 1700*635a8641SAndroid Build Coastguard Worker self.pop_context_reference() 1701*635a8641SAndroid Build Coastguard Worker 1702*635a8641SAndroid Build Coastguard Worker def visit_EvalContextModifier(self, node, frame): 1703*635a8641SAndroid Build Coastguard Worker for keyword in node.options: 1704*635a8641SAndroid Build Coastguard Worker self.writeline('context.eval_ctx.%s = ' % keyword.key) 1705*635a8641SAndroid Build Coastguard Worker self.visit(keyword.value, frame) 1706*635a8641SAndroid Build Coastguard Worker try: 1707*635a8641SAndroid Build Coastguard Worker val = keyword.value.as_const(frame.eval_ctx) 1708*635a8641SAndroid Build Coastguard Worker except nodes.Impossible: 1709*635a8641SAndroid Build Coastguard Worker frame.eval_ctx.volatile = True 1710*635a8641SAndroid Build Coastguard Worker else: 1711*635a8641SAndroid Build Coastguard Worker setattr(frame.eval_ctx, keyword.key, val) 1712*635a8641SAndroid Build Coastguard Worker 1713*635a8641SAndroid Build Coastguard Worker def visit_ScopedEvalContextModifier(self, node, frame): 1714*635a8641SAndroid Build Coastguard Worker old_ctx_name = self.temporary_identifier() 1715*635a8641SAndroid Build Coastguard Worker saved_ctx = frame.eval_ctx.save() 1716*635a8641SAndroid Build Coastguard Worker self.writeline('%s = context.eval_ctx.save()' % old_ctx_name) 1717*635a8641SAndroid Build Coastguard Worker self.visit_EvalContextModifier(node, frame) 1718*635a8641SAndroid Build Coastguard Worker for child in node.body: 1719*635a8641SAndroid Build Coastguard Worker self.visit(child, frame) 1720*635a8641SAndroid Build Coastguard Worker frame.eval_ctx.revert(saved_ctx) 1721*635a8641SAndroid Build Coastguard Worker self.writeline('context.eval_ctx.revert(%s)' % old_ctx_name) 1722