1# -*- coding: utf-8 -*- 2""" 3 jinja2.parser 4 ~~~~~~~~~~~~~ 5 6 Implements the template parser. 7 8 :copyright: (c) 2017 by the Jinja Team. 9 :license: BSD, see LICENSE for more details. 10""" 11from jinja2 import nodes 12from jinja2.exceptions import TemplateSyntaxError, TemplateAssertionError 13from jinja2.lexer import describe_token, describe_token_expr 14from jinja2._compat import imap 15 16 17_statement_keywords = frozenset(['for', 'if', 'block', 'extends', 'print', 18 'macro', 'include', 'from', 'import', 19 'set', 'with', 'autoescape']) 20_compare_operators = frozenset(['eq', 'ne', 'lt', 'lteq', 'gt', 'gteq']) 21 22_math_nodes = { 23 'add': nodes.Add, 24 'sub': nodes.Sub, 25 'mul': nodes.Mul, 26 'div': nodes.Div, 27 'floordiv': nodes.FloorDiv, 28 'mod': nodes.Mod, 29} 30 31 32class Parser(object): 33 """This is the central parsing class Jinja2 uses. It's passed to 34 extensions and can be used to parse expressions or statements. 35 """ 36 37 def __init__(self, environment, source, name=None, filename=None, 38 state=None): 39 self.environment = environment 40 self.stream = environment._tokenize(source, name, filename, state) 41 self.name = name 42 self.filename = filename 43 self.closed = False 44 self.extensions = {} 45 for extension in environment.iter_extensions(): 46 for tag in extension.tags: 47 self.extensions[tag] = extension.parse 48 self._last_identifier = 0 49 self._tag_stack = [] 50 self._end_token_stack = [] 51 52 def fail(self, msg, lineno=None, exc=TemplateSyntaxError): 53 """Convenience method that raises `exc` with the message, passed 54 line number or last line number as well as the current name and 55 filename. 56 """ 57 if lineno is None: 58 lineno = self.stream.current.lineno 59 raise exc(msg, lineno, self.name, self.filename) 60 61 def _fail_ut_eof(self, name, end_token_stack, lineno): 62 expected = [] 63 for exprs in end_token_stack: 64 expected.extend(imap(describe_token_expr, exprs)) 65 if end_token_stack: 66 currently_looking = ' or '.join( 67 "'%s'" % describe_token_expr(expr) 68 for expr in end_token_stack[-1]) 69 else: 70 currently_looking = None 71 72 if name is None: 73 message = ['Unexpected end of template.'] 74 else: 75 message = ['Encountered unknown tag \'%s\'.' % name] 76 77 if currently_looking: 78 if name is not None and name in expected: 79 message.append('You probably made a nesting mistake. Jinja ' 80 'is expecting this tag, but currently looking ' 81 'for %s.' % currently_looking) 82 else: 83 message.append('Jinja was looking for the following tags: ' 84 '%s.' % currently_looking) 85 86 if self._tag_stack: 87 message.append('The innermost block that needs to be ' 88 'closed is \'%s\'.' % self._tag_stack[-1]) 89 90 self.fail(' '.join(message), lineno) 91 92 def fail_unknown_tag(self, name, lineno=None): 93 """Called if the parser encounters an unknown tag. Tries to fail 94 with a human readable error message that could help to identify 95 the problem. 96 """ 97 return self._fail_ut_eof(name, self._end_token_stack, lineno) 98 99 def fail_eof(self, end_tokens=None, lineno=None): 100 """Like fail_unknown_tag but for end of template situations.""" 101 stack = list(self._end_token_stack) 102 if end_tokens is not None: 103 stack.append(end_tokens) 104 return self._fail_ut_eof(None, stack, lineno) 105 106 def is_tuple_end(self, extra_end_rules=None): 107 """Are we at the end of a tuple?""" 108 if self.stream.current.type in ('variable_end', 'block_end', 'rparen'): 109 return True 110 elif extra_end_rules is not None: 111 return self.stream.current.test_any(extra_end_rules) 112 return False 113 114 def free_identifier(self, lineno=None): 115 """Return a new free identifier as :class:`~jinja2.nodes.InternalName`.""" 116 self._last_identifier += 1 117 rv = object.__new__(nodes.InternalName) 118 nodes.Node.__init__(rv, 'fi%d' % self._last_identifier, lineno=lineno) 119 return rv 120 121 def parse_statement(self): 122 """Parse a single statement.""" 123 token = self.stream.current 124 if token.type != 'name': 125 self.fail('tag name expected', token.lineno) 126 self._tag_stack.append(token.value) 127 pop_tag = True 128 try: 129 if token.value in _statement_keywords: 130 return getattr(self, 'parse_' + self.stream.current.value)() 131 if token.value == 'call': 132 return self.parse_call_block() 133 if token.value == 'filter': 134 return self.parse_filter_block() 135 ext = self.extensions.get(token.value) 136 if ext is not None: 137 return ext(self) 138 139 # did not work out, remove the token we pushed by accident 140 # from the stack so that the unknown tag fail function can 141 # produce a proper error message. 142 self._tag_stack.pop() 143 pop_tag = False 144 self.fail_unknown_tag(token.value, token.lineno) 145 finally: 146 if pop_tag: 147 self._tag_stack.pop() 148 149 def parse_statements(self, end_tokens, drop_needle=False): 150 """Parse multiple statements into a list until one of the end tokens 151 is reached. This is used to parse the body of statements as it also 152 parses template data if appropriate. The parser checks first if the 153 current token is a colon and skips it if there is one. Then it checks 154 for the block end and parses until if one of the `end_tokens` is 155 reached. Per default the active token in the stream at the end of 156 the call is the matched end token. If this is not wanted `drop_needle` 157 can be set to `True` and the end token is removed. 158 """ 159 # the first token may be a colon for python compatibility 160 self.stream.skip_if('colon') 161 162 # in the future it would be possible to add whole code sections 163 # by adding some sort of end of statement token and parsing those here. 164 self.stream.expect('block_end') 165 result = self.subparse(end_tokens) 166 167 # we reached the end of the template too early, the subparser 168 # does not check for this, so we do that now 169 if self.stream.current.type == 'eof': 170 self.fail_eof(end_tokens) 171 172 if drop_needle: 173 next(self.stream) 174 return result 175 176 def parse_set(self): 177 """Parse an assign statement.""" 178 lineno = next(self.stream).lineno 179 target = self.parse_assign_target() 180 if self.stream.skip_if('assign'): 181 expr = self.parse_tuple() 182 return nodes.Assign(target, expr, lineno=lineno) 183 body = self.parse_statements(('name:endset',), 184 drop_needle=True) 185 return nodes.AssignBlock(target, body, lineno=lineno) 186 187 def parse_for(self): 188 """Parse a for loop.""" 189 lineno = self.stream.expect('name:for').lineno 190 target = self.parse_assign_target(extra_end_rules=('name:in',)) 191 self.stream.expect('name:in') 192 iter = self.parse_tuple(with_condexpr=False, 193 extra_end_rules=('name:recursive',)) 194 test = None 195 if self.stream.skip_if('name:if'): 196 test = self.parse_expression() 197 recursive = self.stream.skip_if('name:recursive') 198 body = self.parse_statements(('name:endfor', 'name:else')) 199 if next(self.stream).value == 'endfor': 200 else_ = [] 201 else: 202 else_ = self.parse_statements(('name:endfor',), drop_needle=True) 203 return nodes.For(target, iter, body, else_, test, 204 recursive, lineno=lineno) 205 206 def parse_if(self): 207 """Parse an if construct.""" 208 node = result = nodes.If(lineno=self.stream.expect('name:if').lineno) 209 while 1: 210 node.test = self.parse_tuple(with_condexpr=False) 211 node.body = self.parse_statements(('name:elif', 'name:else', 212 'name:endif')) 213 token = next(self.stream) 214 if token.test('name:elif'): 215 new_node = nodes.If(lineno=self.stream.current.lineno) 216 node.else_ = [new_node] 217 node = new_node 218 continue 219 elif token.test('name:else'): 220 node.else_ = self.parse_statements(('name:endif',), 221 drop_needle=True) 222 else: 223 node.else_ = [] 224 break 225 return result 226 227 def parse_with(self): 228 node = nodes.With(lineno=next(self.stream).lineno) 229 targets = [] 230 values = [] 231 while self.stream.current.type != 'block_end': 232 lineno = self.stream.current.lineno 233 if targets: 234 self.stream.expect('comma') 235 target = self.parse_assign_target() 236 target.set_ctx('param') 237 targets.append(target) 238 self.stream.expect('assign') 239 values.append(self.parse_expression()) 240 node.targets = targets 241 node.values = values 242 node.body = self.parse_statements(('name:endwith',), 243 drop_needle=True) 244 return node 245 246 def parse_autoescape(self): 247 node = nodes.ScopedEvalContextModifier(lineno=next(self.stream).lineno) 248 node.options = [ 249 nodes.Keyword('autoescape', self.parse_expression()) 250 ] 251 node.body = self.parse_statements(('name:endautoescape',), 252 drop_needle=True) 253 return nodes.Scope([node]) 254 255 def parse_block(self): 256 node = nodes.Block(lineno=next(self.stream).lineno) 257 node.name = self.stream.expect('name').value 258 node.scoped = self.stream.skip_if('name:scoped') 259 260 # common problem people encounter when switching from django 261 # to jinja. we do not support hyphens in block names, so let's 262 # raise a nicer error message in that case. 263 if self.stream.current.type == 'sub': 264 self.fail('Block names in Jinja have to be valid Python ' 265 'identifiers and may not contain hyphens, use an ' 266 'underscore instead.') 267 268 node.body = self.parse_statements(('name:endblock',), drop_needle=True) 269 self.stream.skip_if('name:' + node.name) 270 return node 271 272 def parse_extends(self): 273 node = nodes.Extends(lineno=next(self.stream).lineno) 274 node.template = self.parse_expression() 275 return node 276 277 def parse_import_context(self, node, default): 278 if self.stream.current.test_any('name:with', 'name:without') and \ 279 self.stream.look().test('name:context'): 280 node.with_context = next(self.stream).value == 'with' 281 self.stream.skip() 282 else: 283 node.with_context = default 284 return node 285 286 def parse_include(self): 287 node = nodes.Include(lineno=next(self.stream).lineno) 288 node.template = self.parse_expression() 289 if self.stream.current.test('name:ignore') and \ 290 self.stream.look().test('name:missing'): 291 node.ignore_missing = True 292 self.stream.skip(2) 293 else: 294 node.ignore_missing = False 295 return self.parse_import_context(node, True) 296 297 def parse_import(self): 298 node = nodes.Import(lineno=next(self.stream).lineno) 299 node.template = self.parse_expression() 300 self.stream.expect('name:as') 301 node.target = self.parse_assign_target(name_only=True).name 302 return self.parse_import_context(node, False) 303 304 def parse_from(self): 305 node = nodes.FromImport(lineno=next(self.stream).lineno) 306 node.template = self.parse_expression() 307 self.stream.expect('name:import') 308 node.names = [] 309 310 def parse_context(): 311 if self.stream.current.value in ('with', 'without') and \ 312 self.stream.look().test('name:context'): 313 node.with_context = next(self.stream).value == 'with' 314 self.stream.skip() 315 return True 316 return False 317 318 while 1: 319 if node.names: 320 self.stream.expect('comma') 321 if self.stream.current.type == 'name': 322 if parse_context(): 323 break 324 target = self.parse_assign_target(name_only=True) 325 if target.name.startswith('_'): 326 self.fail('names starting with an underline can not ' 327 'be imported', target.lineno, 328 exc=TemplateAssertionError) 329 if self.stream.skip_if('name:as'): 330 alias = self.parse_assign_target(name_only=True) 331 node.names.append((target.name, alias.name)) 332 else: 333 node.names.append(target.name) 334 if parse_context() or self.stream.current.type != 'comma': 335 break 336 else: 337 break 338 if not hasattr(node, 'with_context'): 339 node.with_context = False 340 self.stream.skip_if('comma') 341 return node 342 343 def parse_signature(self, node): 344 node.args = args = [] 345 node.defaults = defaults = [] 346 self.stream.expect('lparen') 347 while self.stream.current.type != 'rparen': 348 if args: 349 self.stream.expect('comma') 350 arg = self.parse_assign_target(name_only=True) 351 arg.set_ctx('param') 352 if self.stream.skip_if('assign'): 353 defaults.append(self.parse_expression()) 354 elif defaults: 355 self.fail('non-default argument follows default argument') 356 args.append(arg) 357 self.stream.expect('rparen') 358 359 def parse_call_block(self): 360 node = nodes.CallBlock(lineno=next(self.stream).lineno) 361 if self.stream.current.type == 'lparen': 362 self.parse_signature(node) 363 else: 364 node.args = [] 365 node.defaults = [] 366 367 node.call = self.parse_expression() 368 if not isinstance(node.call, nodes.Call): 369 self.fail('expected call', node.lineno) 370 node.body = self.parse_statements(('name:endcall',), drop_needle=True) 371 return node 372 373 def parse_filter_block(self): 374 node = nodes.FilterBlock(lineno=next(self.stream).lineno) 375 node.filter = self.parse_filter(None, start_inline=True) 376 node.body = self.parse_statements(('name:endfilter',), 377 drop_needle=True) 378 return node 379 380 def parse_macro(self): 381 node = nodes.Macro(lineno=next(self.stream).lineno) 382 node.name = self.parse_assign_target(name_only=True).name 383 self.parse_signature(node) 384 node.body = self.parse_statements(('name:endmacro',), 385 drop_needle=True) 386 return node 387 388 def parse_print(self): 389 node = nodes.Output(lineno=next(self.stream).lineno) 390 node.nodes = [] 391 while self.stream.current.type != 'block_end': 392 if node.nodes: 393 self.stream.expect('comma') 394 node.nodes.append(self.parse_expression()) 395 return node 396 397 def parse_assign_target(self, with_tuple=True, name_only=False, 398 extra_end_rules=None): 399 """Parse an assignment target. As Jinja2 allows assignments to 400 tuples, this function can parse all allowed assignment targets. Per 401 default assignments to tuples are parsed, that can be disable however 402 by setting `with_tuple` to `False`. If only assignments to names are 403 wanted `name_only` can be set to `True`. The `extra_end_rules` 404 parameter is forwarded to the tuple parsing function. 405 """ 406 if name_only: 407 token = self.stream.expect('name') 408 target = nodes.Name(token.value, 'store', lineno=token.lineno) 409 else: 410 if with_tuple: 411 target = self.parse_tuple(simplified=True, 412 extra_end_rules=extra_end_rules) 413 else: 414 target = self.parse_primary() 415 target.set_ctx('store') 416 if not target.can_assign(): 417 self.fail('can\'t assign to %r' % target.__class__. 418 __name__.lower(), target.lineno) 419 return target 420 421 def parse_expression(self, with_condexpr=True): 422 """Parse an expression. Per default all expressions are parsed, if 423 the optional `with_condexpr` parameter is set to `False` conditional 424 expressions are not parsed. 425 """ 426 if with_condexpr: 427 return self.parse_condexpr() 428 return self.parse_or() 429 430 def parse_condexpr(self): 431 lineno = self.stream.current.lineno 432 expr1 = self.parse_or() 433 while self.stream.skip_if('name:if'): 434 expr2 = self.parse_or() 435 if self.stream.skip_if('name:else'): 436 expr3 = self.parse_condexpr() 437 else: 438 expr3 = None 439 expr1 = nodes.CondExpr(expr2, expr1, expr3, lineno=lineno) 440 lineno = self.stream.current.lineno 441 return expr1 442 443 def parse_or(self): 444 lineno = self.stream.current.lineno 445 left = self.parse_and() 446 while self.stream.skip_if('name:or'): 447 right = self.parse_and() 448 left = nodes.Or(left, right, lineno=lineno) 449 lineno = self.stream.current.lineno 450 return left 451 452 def parse_and(self): 453 lineno = self.stream.current.lineno 454 left = self.parse_not() 455 while self.stream.skip_if('name:and'): 456 right = self.parse_not() 457 left = nodes.And(left, right, lineno=lineno) 458 lineno = self.stream.current.lineno 459 return left 460 461 def parse_not(self): 462 if self.stream.current.test('name:not'): 463 lineno = next(self.stream).lineno 464 return nodes.Not(self.parse_not(), lineno=lineno) 465 return self.parse_compare() 466 467 def parse_compare(self): 468 lineno = self.stream.current.lineno 469 expr = self.parse_math1() 470 ops = [] 471 while 1: 472 token_type = self.stream.current.type 473 if token_type in _compare_operators: 474 next(self.stream) 475 ops.append(nodes.Operand(token_type, self.parse_math1())) 476 elif self.stream.skip_if('name:in'): 477 ops.append(nodes.Operand('in', self.parse_math1())) 478 elif (self.stream.current.test('name:not') and 479 self.stream.look().test('name:in')): 480 self.stream.skip(2) 481 ops.append(nodes.Operand('notin', self.parse_math1())) 482 else: 483 break 484 lineno = self.stream.current.lineno 485 if not ops: 486 return expr 487 return nodes.Compare(expr, ops, lineno=lineno) 488 489 def parse_math1(self): 490 lineno = self.stream.current.lineno 491 left = self.parse_concat() 492 while self.stream.current.type in ('add', 'sub'): 493 cls = _math_nodes[self.stream.current.type] 494 next(self.stream) 495 right = self.parse_concat() 496 left = cls(left, right, lineno=lineno) 497 lineno = self.stream.current.lineno 498 return left 499 500 def parse_concat(self): 501 lineno = self.stream.current.lineno 502 args = [self.parse_math2()] 503 while self.stream.current.type == 'tilde': 504 next(self.stream) 505 args.append(self.parse_math2()) 506 if len(args) == 1: 507 return args[0] 508 return nodes.Concat(args, lineno=lineno) 509 510 def parse_math2(self): 511 lineno = self.stream.current.lineno 512 left = self.parse_pow() 513 while self.stream.current.type in ('mul', 'div', 'floordiv', 'mod'): 514 cls = _math_nodes[self.stream.current.type] 515 next(self.stream) 516 right = self.parse_pow() 517 left = cls(left, right, lineno=lineno) 518 lineno = self.stream.current.lineno 519 return left 520 521 def parse_pow(self): 522 lineno = self.stream.current.lineno 523 left = self.parse_unary() 524 while self.stream.current.type == 'pow': 525 next(self.stream) 526 right = self.parse_unary() 527 left = nodes.Pow(left, right, lineno=lineno) 528 lineno = self.stream.current.lineno 529 return left 530 531 def parse_unary(self, with_filter=True): 532 token_type = self.stream.current.type 533 lineno = self.stream.current.lineno 534 if token_type == 'sub': 535 next(self.stream) 536 node = nodes.Neg(self.parse_unary(False), lineno=lineno) 537 elif token_type == 'add': 538 next(self.stream) 539 node = nodes.Pos(self.parse_unary(False), lineno=lineno) 540 else: 541 node = self.parse_primary() 542 node = self.parse_postfix(node) 543 if with_filter: 544 node = self.parse_filter_expr(node) 545 return node 546 547 def parse_primary(self): 548 token = self.stream.current 549 if token.type == 'name': 550 if token.value in ('true', 'false', 'True', 'False'): 551 node = nodes.Const(token.value in ('true', 'True'), 552 lineno=token.lineno) 553 elif token.value in ('none', 'None'): 554 node = nodes.Const(None, lineno=token.lineno) 555 else: 556 node = nodes.Name(token.value, 'load', lineno=token.lineno) 557 next(self.stream) 558 elif token.type == 'string': 559 next(self.stream) 560 buf = [token.value] 561 lineno = token.lineno 562 while self.stream.current.type == 'string': 563 buf.append(self.stream.current.value) 564 next(self.stream) 565 node = nodes.Const(''.join(buf), lineno=lineno) 566 elif token.type in ('integer', 'float'): 567 next(self.stream) 568 node = nodes.Const(token.value, lineno=token.lineno) 569 elif token.type == 'lparen': 570 next(self.stream) 571 node = self.parse_tuple(explicit_parentheses=True) 572 self.stream.expect('rparen') 573 elif token.type == 'lbracket': 574 node = self.parse_list() 575 elif token.type == 'lbrace': 576 node = self.parse_dict() 577 else: 578 self.fail("unexpected '%s'" % describe_token(token), token.lineno) 579 return node 580 581 def parse_tuple(self, simplified=False, with_condexpr=True, 582 extra_end_rules=None, explicit_parentheses=False): 583 """Works like `parse_expression` but if multiple expressions are 584 delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created. 585 This method could also return a regular expression instead of a tuple 586 if no commas where found. 587 588 The default parsing mode is a full tuple. If `simplified` is `True` 589 only names and literals are parsed. The `no_condexpr` parameter is 590 forwarded to :meth:`parse_expression`. 591 592 Because tuples do not require delimiters and may end in a bogus comma 593 an extra hint is needed that marks the end of a tuple. For example 594 for loops support tuples between `for` and `in`. In that case the 595 `extra_end_rules` is set to ``['name:in']``. 596 597 `explicit_parentheses` is true if the parsing was triggered by an 598 expression in parentheses. This is used to figure out if an empty 599 tuple is a valid expression or not. 600 """ 601 lineno = self.stream.current.lineno 602 if simplified: 603 parse = self.parse_primary 604 elif with_condexpr: 605 parse = self.parse_expression 606 else: 607 parse = lambda: self.parse_expression(with_condexpr=False) 608 args = [] 609 is_tuple = False 610 while 1: 611 if args: 612 self.stream.expect('comma') 613 if self.is_tuple_end(extra_end_rules): 614 break 615 args.append(parse()) 616 if self.stream.current.type == 'comma': 617 is_tuple = True 618 else: 619 break 620 lineno = self.stream.current.lineno 621 622 if not is_tuple: 623 if args: 624 return args[0] 625 626 # if we don't have explicit parentheses, an empty tuple is 627 # not a valid expression. This would mean nothing (literally 628 # nothing) in the spot of an expression would be an empty 629 # tuple. 630 if not explicit_parentheses: 631 self.fail('Expected an expression, got \'%s\'' % 632 describe_token(self.stream.current)) 633 634 return nodes.Tuple(args, 'load', lineno=lineno) 635 636 def parse_list(self): 637 token = self.stream.expect('lbracket') 638 items = [] 639 while self.stream.current.type != 'rbracket': 640 if items: 641 self.stream.expect('comma') 642 if self.stream.current.type == 'rbracket': 643 break 644 items.append(self.parse_expression()) 645 self.stream.expect('rbracket') 646 return nodes.List(items, lineno=token.lineno) 647 648 def parse_dict(self): 649 token = self.stream.expect('lbrace') 650 items = [] 651 while self.stream.current.type != 'rbrace': 652 if items: 653 self.stream.expect('comma') 654 if self.stream.current.type == 'rbrace': 655 break 656 key = self.parse_expression() 657 self.stream.expect('colon') 658 value = self.parse_expression() 659 items.append(nodes.Pair(key, value, lineno=key.lineno)) 660 self.stream.expect('rbrace') 661 return nodes.Dict(items, lineno=token.lineno) 662 663 def parse_postfix(self, node): 664 while 1: 665 token_type = self.stream.current.type 666 if token_type == 'dot' or token_type == 'lbracket': 667 node = self.parse_subscript(node) 668 # calls are valid both after postfix expressions (getattr 669 # and getitem) as well as filters and tests 670 elif token_type == 'lparen': 671 node = self.parse_call(node) 672 else: 673 break 674 return node 675 676 def parse_filter_expr(self, node): 677 while 1: 678 token_type = self.stream.current.type 679 if token_type == 'pipe': 680 node = self.parse_filter(node) 681 elif token_type == 'name' and self.stream.current.value == 'is': 682 node = self.parse_test(node) 683 # calls are valid both after postfix expressions (getattr 684 # and getitem) as well as filters and tests 685 elif token_type == 'lparen': 686 node = self.parse_call(node) 687 else: 688 break 689 return node 690 691 def parse_subscript(self, node): 692 token = next(self.stream) 693 if token.type == 'dot': 694 attr_token = self.stream.current 695 next(self.stream) 696 if attr_token.type == 'name': 697 return nodes.Getattr(node, attr_token.value, 'load', 698 lineno=token.lineno) 699 elif attr_token.type != 'integer': 700 self.fail('expected name or number', attr_token.lineno) 701 arg = nodes.Const(attr_token.value, lineno=attr_token.lineno) 702 return nodes.Getitem(node, arg, 'load', lineno=token.lineno) 703 if token.type == 'lbracket': 704 args = [] 705 while self.stream.current.type != 'rbracket': 706 if args: 707 self.stream.expect('comma') 708 args.append(self.parse_subscribed()) 709 self.stream.expect('rbracket') 710 if len(args) == 1: 711 arg = args[0] 712 else: 713 arg = nodes.Tuple(args, 'load', lineno=token.lineno) 714 return nodes.Getitem(node, arg, 'load', lineno=token.lineno) 715 self.fail('expected subscript expression', self.lineno) 716 717 def parse_subscribed(self): 718 lineno = self.stream.current.lineno 719 720 if self.stream.current.type == 'colon': 721 next(self.stream) 722 args = [None] 723 else: 724 node = self.parse_expression() 725 if self.stream.current.type != 'colon': 726 return node 727 next(self.stream) 728 args = [node] 729 730 if self.stream.current.type == 'colon': 731 args.append(None) 732 elif self.stream.current.type not in ('rbracket', 'comma'): 733 args.append(self.parse_expression()) 734 else: 735 args.append(None) 736 737 if self.stream.current.type == 'colon': 738 next(self.stream) 739 if self.stream.current.type not in ('rbracket', 'comma'): 740 args.append(self.parse_expression()) 741 else: 742 args.append(None) 743 else: 744 args.append(None) 745 746 return nodes.Slice(lineno=lineno, *args) 747 748 def parse_call(self, node): 749 token = self.stream.expect('lparen') 750 args = [] 751 kwargs = [] 752 dyn_args = dyn_kwargs = None 753 require_comma = False 754 755 def ensure(expr): 756 if not expr: 757 self.fail('invalid syntax for function call expression', 758 token.lineno) 759 760 while self.stream.current.type != 'rparen': 761 if require_comma: 762 self.stream.expect('comma') 763 # support for trailing comma 764 if self.stream.current.type == 'rparen': 765 break 766 if self.stream.current.type == 'mul': 767 ensure(dyn_args is None and dyn_kwargs is None) 768 next(self.stream) 769 dyn_args = self.parse_expression() 770 elif self.stream.current.type == 'pow': 771 ensure(dyn_kwargs is None) 772 next(self.stream) 773 dyn_kwargs = self.parse_expression() 774 else: 775 ensure(dyn_args is None and dyn_kwargs is None) 776 if self.stream.current.type == 'name' and \ 777 self.stream.look().type == 'assign': 778 key = self.stream.current.value 779 self.stream.skip(2) 780 value = self.parse_expression() 781 kwargs.append(nodes.Keyword(key, value, 782 lineno=value.lineno)) 783 else: 784 ensure(not kwargs) 785 args.append(self.parse_expression()) 786 787 require_comma = True 788 self.stream.expect('rparen') 789 790 if node is None: 791 return args, kwargs, dyn_args, dyn_kwargs 792 return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs, 793 lineno=token.lineno) 794 795 def parse_filter(self, node, start_inline=False): 796 while self.stream.current.type == 'pipe' or start_inline: 797 if not start_inline: 798 next(self.stream) 799 token = self.stream.expect('name') 800 name = token.value 801 while self.stream.current.type == 'dot': 802 next(self.stream) 803 name += '.' + self.stream.expect('name').value 804 if self.stream.current.type == 'lparen': 805 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None) 806 else: 807 args = [] 808 kwargs = [] 809 dyn_args = dyn_kwargs = None 810 node = nodes.Filter(node, name, args, kwargs, dyn_args, 811 dyn_kwargs, lineno=token.lineno) 812 start_inline = False 813 return node 814 815 def parse_test(self, node): 816 token = next(self.stream) 817 if self.stream.current.test('name:not'): 818 next(self.stream) 819 negated = True 820 else: 821 negated = False 822 name = self.stream.expect('name').value 823 while self.stream.current.type == 'dot': 824 next(self.stream) 825 name += '.' + self.stream.expect('name').value 826 dyn_args = dyn_kwargs = None 827 kwargs = [] 828 if self.stream.current.type == 'lparen': 829 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None) 830 elif (self.stream.current.type in ('name', 'string', 'integer', 831 'float', 'lparen', 'lbracket', 832 'lbrace') and not 833 self.stream.current.test_any('name:else', 'name:or', 834 'name:and')): 835 if self.stream.current.test('name:is'): 836 self.fail('You cannot chain multiple tests with is') 837 args = [self.parse_primary()] 838 else: 839 args = [] 840 node = nodes.Test(node, name, args, kwargs, dyn_args, 841 dyn_kwargs, lineno=token.lineno) 842 if negated: 843 node = nodes.Not(node, lineno=token.lineno) 844 return node 845 846 def subparse(self, end_tokens=None): 847 body = [] 848 data_buffer = [] 849 add_data = data_buffer.append 850 851 if end_tokens is not None: 852 self._end_token_stack.append(end_tokens) 853 854 def flush_data(): 855 if data_buffer: 856 lineno = data_buffer[0].lineno 857 body.append(nodes.Output(data_buffer[:], lineno=lineno)) 858 del data_buffer[:] 859 860 try: 861 while self.stream: 862 token = self.stream.current 863 if token.type == 'data': 864 if token.value: 865 add_data(nodes.TemplateData(token.value, 866 lineno=token.lineno)) 867 next(self.stream) 868 elif token.type == 'variable_begin': 869 next(self.stream) 870 add_data(self.parse_tuple(with_condexpr=True)) 871 self.stream.expect('variable_end') 872 elif token.type == 'block_begin': 873 flush_data() 874 next(self.stream) 875 if end_tokens is not None and \ 876 self.stream.current.test_any(*end_tokens): 877 return body 878 rv = self.parse_statement() 879 if isinstance(rv, list): 880 body.extend(rv) 881 else: 882 body.append(rv) 883 self.stream.expect('block_end') 884 else: 885 raise AssertionError('internal parsing error') 886 887 flush_data() 888 finally: 889 if end_tokens is not None: 890 self._end_token_stack.pop() 891 892 return body 893 894 def parse(self): 895 """Parse the whole template into a `Template` node.""" 896 result = nodes.Template(self.subparse(), lineno=1) 897 result.set_environment(self.environment) 898 return result 899