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(with_namespace=True) 180 if self.stream.skip_if('assign'): 181 expr = self.parse_tuple() 182 return nodes.Assign(target, expr, lineno=lineno) 183 filter_node = self.parse_filter(None) 184 body = self.parse_statements(('name:endset',), 185 drop_needle=True) 186 return nodes.AssignBlock(target, filter_node, body, lineno=lineno) 187 188 def parse_for(self): 189 """Parse a for loop.""" 190 lineno = self.stream.expect('name:for').lineno 191 target = self.parse_assign_target(extra_end_rules=('name:in',)) 192 self.stream.expect('name:in') 193 iter = self.parse_tuple(with_condexpr=False, 194 extra_end_rules=('name:recursive',)) 195 test = None 196 if self.stream.skip_if('name:if'): 197 test = self.parse_expression() 198 recursive = self.stream.skip_if('name:recursive') 199 body = self.parse_statements(('name:endfor', 'name:else')) 200 if next(self.stream).value == 'endfor': 201 else_ = [] 202 else: 203 else_ = self.parse_statements(('name:endfor',), drop_needle=True) 204 return nodes.For(target, iter, body, else_, test, 205 recursive, lineno=lineno) 206 207 def parse_if(self): 208 """Parse an if construct.""" 209 node = result = nodes.If(lineno=self.stream.expect('name:if').lineno) 210 while 1: 211 node.test = self.parse_tuple(with_condexpr=False) 212 node.body = self.parse_statements(('name:elif', 'name:else', 213 'name:endif')) 214 node.elif_ = [] 215 node.else_ = [] 216 token = next(self.stream) 217 if token.test('name:elif'): 218 node = nodes.If(lineno=self.stream.current.lineno) 219 result.elif_.append(node) 220 continue 221 elif token.test('name:else'): 222 result.else_ = self.parse_statements(('name:endif',), 223 drop_needle=True) 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 self.stream.expect('name') 338 if not hasattr(node, 'with_context'): 339 node.with_context = False 340 return node 341 342 def parse_signature(self, node): 343 node.args = args = [] 344 node.defaults = defaults = [] 345 self.stream.expect('lparen') 346 while self.stream.current.type != 'rparen': 347 if args: 348 self.stream.expect('comma') 349 arg = self.parse_assign_target(name_only=True) 350 arg.set_ctx('param') 351 if self.stream.skip_if('assign'): 352 defaults.append(self.parse_expression()) 353 elif defaults: 354 self.fail('non-default argument follows default argument') 355 args.append(arg) 356 self.stream.expect('rparen') 357 358 def parse_call_block(self): 359 node = nodes.CallBlock(lineno=next(self.stream).lineno) 360 if self.stream.current.type == 'lparen': 361 self.parse_signature(node) 362 else: 363 node.args = [] 364 node.defaults = [] 365 366 node.call = self.parse_expression() 367 if not isinstance(node.call, nodes.Call): 368 self.fail('expected call', node.lineno) 369 node.body = self.parse_statements(('name:endcall',), drop_needle=True) 370 return node 371 372 def parse_filter_block(self): 373 node = nodes.FilterBlock(lineno=next(self.stream).lineno) 374 node.filter = self.parse_filter(None, start_inline=True) 375 node.body = self.parse_statements(('name:endfilter',), 376 drop_needle=True) 377 return node 378 379 def parse_macro(self): 380 node = nodes.Macro(lineno=next(self.stream).lineno) 381 node.name = self.parse_assign_target(name_only=True).name 382 self.parse_signature(node) 383 node.body = self.parse_statements(('name:endmacro',), 384 drop_needle=True) 385 return node 386 387 def parse_print(self): 388 node = nodes.Output(lineno=next(self.stream).lineno) 389 node.nodes = [] 390 while self.stream.current.type != 'block_end': 391 if node.nodes: 392 self.stream.expect('comma') 393 node.nodes.append(self.parse_expression()) 394 return node 395 396 def parse_assign_target(self, with_tuple=True, name_only=False, 397 extra_end_rules=None, with_namespace=False): 398 """Parse an assignment target. As Jinja2 allows assignments to 399 tuples, this function can parse all allowed assignment targets. Per 400 default assignments to tuples are parsed, that can be disable however 401 by setting `with_tuple` to `False`. If only assignments to names are 402 wanted `name_only` can be set to `True`. The `extra_end_rules` 403 parameter is forwarded to the tuple parsing function. If 404 `with_namespace` is enabled, a namespace assignment may be parsed. 405 """ 406 if with_namespace and self.stream.look().type == 'dot': 407 token = self.stream.expect('name') 408 next(self.stream) # dot 409 attr = self.stream.expect('name') 410 target = nodes.NSRef(token.value, attr.value, lineno=token.lineno) 411 elif name_only: 412 token = self.stream.expect('name') 413 target = nodes.Name(token.value, 'store', lineno=token.lineno) 414 else: 415 if with_tuple: 416 target = self.parse_tuple(simplified=True, 417 extra_end_rules=extra_end_rules) 418 else: 419 target = self.parse_primary() 420 target.set_ctx('store') 421 if not target.can_assign(): 422 self.fail('can\'t assign to %r' % target.__class__. 423 __name__.lower(), target.lineno) 424 return target 425 426 def parse_expression(self, with_condexpr=True): 427 """Parse an expression. Per default all expressions are parsed, if 428 the optional `with_condexpr` parameter is set to `False` conditional 429 expressions are not parsed. 430 """ 431 if with_condexpr: 432 return self.parse_condexpr() 433 return self.parse_or() 434 435 def parse_condexpr(self): 436 lineno = self.stream.current.lineno 437 expr1 = self.parse_or() 438 while self.stream.skip_if('name:if'): 439 expr2 = self.parse_or() 440 if self.stream.skip_if('name:else'): 441 expr3 = self.parse_condexpr() 442 else: 443 expr3 = None 444 expr1 = nodes.CondExpr(expr2, expr1, expr3, lineno=lineno) 445 lineno = self.stream.current.lineno 446 return expr1 447 448 def parse_or(self): 449 lineno = self.stream.current.lineno 450 left = self.parse_and() 451 while self.stream.skip_if('name:or'): 452 right = self.parse_and() 453 left = nodes.Or(left, right, lineno=lineno) 454 lineno = self.stream.current.lineno 455 return left 456 457 def parse_and(self): 458 lineno = self.stream.current.lineno 459 left = self.parse_not() 460 while self.stream.skip_if('name:and'): 461 right = self.parse_not() 462 left = nodes.And(left, right, lineno=lineno) 463 lineno = self.stream.current.lineno 464 return left 465 466 def parse_not(self): 467 if self.stream.current.test('name:not'): 468 lineno = next(self.stream).lineno 469 return nodes.Not(self.parse_not(), lineno=lineno) 470 return self.parse_compare() 471 472 def parse_compare(self): 473 lineno = self.stream.current.lineno 474 expr = self.parse_math1() 475 ops = [] 476 while 1: 477 token_type = self.stream.current.type 478 if token_type in _compare_operators: 479 next(self.stream) 480 ops.append(nodes.Operand(token_type, self.parse_math1())) 481 elif self.stream.skip_if('name:in'): 482 ops.append(nodes.Operand('in', self.parse_math1())) 483 elif (self.stream.current.test('name:not') and 484 self.stream.look().test('name:in')): 485 self.stream.skip(2) 486 ops.append(nodes.Operand('notin', self.parse_math1())) 487 else: 488 break 489 lineno = self.stream.current.lineno 490 if not ops: 491 return expr 492 return nodes.Compare(expr, ops, lineno=lineno) 493 494 def parse_math1(self): 495 lineno = self.stream.current.lineno 496 left = self.parse_concat() 497 while self.stream.current.type in ('add', 'sub'): 498 cls = _math_nodes[self.stream.current.type] 499 next(self.stream) 500 right = self.parse_concat() 501 left = cls(left, right, lineno=lineno) 502 lineno = self.stream.current.lineno 503 return left 504 505 def parse_concat(self): 506 lineno = self.stream.current.lineno 507 args = [self.parse_math2()] 508 while self.stream.current.type == 'tilde': 509 next(self.stream) 510 args.append(self.parse_math2()) 511 if len(args) == 1: 512 return args[0] 513 return nodes.Concat(args, lineno=lineno) 514 515 def parse_math2(self): 516 lineno = self.stream.current.lineno 517 left = self.parse_pow() 518 while self.stream.current.type in ('mul', 'div', 'floordiv', 'mod'): 519 cls = _math_nodes[self.stream.current.type] 520 next(self.stream) 521 right = self.parse_pow() 522 left = cls(left, right, lineno=lineno) 523 lineno = self.stream.current.lineno 524 return left 525 526 def parse_pow(self): 527 lineno = self.stream.current.lineno 528 left = self.parse_unary() 529 while self.stream.current.type == 'pow': 530 next(self.stream) 531 right = self.parse_unary() 532 left = nodes.Pow(left, right, lineno=lineno) 533 lineno = self.stream.current.lineno 534 return left 535 536 def parse_unary(self, with_filter=True): 537 token_type = self.stream.current.type 538 lineno = self.stream.current.lineno 539 if token_type == 'sub': 540 next(self.stream) 541 node = nodes.Neg(self.parse_unary(False), lineno=lineno) 542 elif token_type == 'add': 543 next(self.stream) 544 node = nodes.Pos(self.parse_unary(False), lineno=lineno) 545 else: 546 node = self.parse_primary() 547 node = self.parse_postfix(node) 548 if with_filter: 549 node = self.parse_filter_expr(node) 550 return node 551 552 def parse_primary(self): 553 token = self.stream.current 554 if token.type == 'name': 555 if token.value in ('true', 'false', 'True', 'False'): 556 node = nodes.Const(token.value in ('true', 'True'), 557 lineno=token.lineno) 558 elif token.value in ('none', 'None'): 559 node = nodes.Const(None, lineno=token.lineno) 560 else: 561 node = nodes.Name(token.value, 'load', lineno=token.lineno) 562 next(self.stream) 563 elif token.type == 'string': 564 next(self.stream) 565 buf = [token.value] 566 lineno = token.lineno 567 while self.stream.current.type == 'string': 568 buf.append(self.stream.current.value) 569 next(self.stream) 570 node = nodes.Const(''.join(buf), lineno=lineno) 571 elif token.type in ('integer', 'float'): 572 next(self.stream) 573 node = nodes.Const(token.value, lineno=token.lineno) 574 elif token.type == 'lparen': 575 next(self.stream) 576 node = self.parse_tuple(explicit_parentheses=True) 577 self.stream.expect('rparen') 578 elif token.type == 'lbracket': 579 node = self.parse_list() 580 elif token.type == 'lbrace': 581 node = self.parse_dict() 582 else: 583 self.fail("unexpected '%s'" % describe_token(token), token.lineno) 584 return node 585 586 def parse_tuple(self, simplified=False, with_condexpr=True, 587 extra_end_rules=None, explicit_parentheses=False): 588 """Works like `parse_expression` but if multiple expressions are 589 delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created. 590 This method could also return a regular expression instead of a tuple 591 if no commas where found. 592 593 The default parsing mode is a full tuple. If `simplified` is `True` 594 only names and literals are parsed. The `no_condexpr` parameter is 595 forwarded to :meth:`parse_expression`. 596 597 Because tuples do not require delimiters and may end in a bogus comma 598 an extra hint is needed that marks the end of a tuple. For example 599 for loops support tuples between `for` and `in`. In that case the 600 `extra_end_rules` is set to ``['name:in']``. 601 602 `explicit_parentheses` is true if the parsing was triggered by an 603 expression in parentheses. This is used to figure out if an empty 604 tuple is a valid expression or not. 605 """ 606 lineno = self.stream.current.lineno 607 if simplified: 608 parse = self.parse_primary 609 elif with_condexpr: 610 parse = self.parse_expression 611 else: 612 parse = lambda: self.parse_expression(with_condexpr=False) 613 args = [] 614 is_tuple = False 615 while 1: 616 if args: 617 self.stream.expect('comma') 618 if self.is_tuple_end(extra_end_rules): 619 break 620 args.append(parse()) 621 if self.stream.current.type == 'comma': 622 is_tuple = True 623 else: 624 break 625 lineno = self.stream.current.lineno 626 627 if not is_tuple: 628 if args: 629 return args[0] 630 631 # if we don't have explicit parentheses, an empty tuple is 632 # not a valid expression. This would mean nothing (literally 633 # nothing) in the spot of an expression would be an empty 634 # tuple. 635 if not explicit_parentheses: 636 self.fail('Expected an expression, got \'%s\'' % 637 describe_token(self.stream.current)) 638 639 return nodes.Tuple(args, 'load', lineno=lineno) 640 641 def parse_list(self): 642 token = self.stream.expect('lbracket') 643 items = [] 644 while self.stream.current.type != 'rbracket': 645 if items: 646 self.stream.expect('comma') 647 if self.stream.current.type == 'rbracket': 648 break 649 items.append(self.parse_expression()) 650 self.stream.expect('rbracket') 651 return nodes.List(items, lineno=token.lineno) 652 653 def parse_dict(self): 654 token = self.stream.expect('lbrace') 655 items = [] 656 while self.stream.current.type != 'rbrace': 657 if items: 658 self.stream.expect('comma') 659 if self.stream.current.type == 'rbrace': 660 break 661 key = self.parse_expression() 662 self.stream.expect('colon') 663 value = self.parse_expression() 664 items.append(nodes.Pair(key, value, lineno=key.lineno)) 665 self.stream.expect('rbrace') 666 return nodes.Dict(items, lineno=token.lineno) 667 668 def parse_postfix(self, node): 669 while 1: 670 token_type = self.stream.current.type 671 if token_type == 'dot' or token_type == 'lbracket': 672 node = self.parse_subscript(node) 673 # calls are valid both after postfix expressions (getattr 674 # and getitem) as well as filters and tests 675 elif token_type == 'lparen': 676 node = self.parse_call(node) 677 else: 678 break 679 return node 680 681 def parse_filter_expr(self, node): 682 while 1: 683 token_type = self.stream.current.type 684 if token_type == 'pipe': 685 node = self.parse_filter(node) 686 elif token_type == 'name' and self.stream.current.value == 'is': 687 node = self.parse_test(node) 688 # calls are valid both after postfix expressions (getattr 689 # and getitem) as well as filters and tests 690 elif token_type == 'lparen': 691 node = self.parse_call(node) 692 else: 693 break 694 return node 695 696 def parse_subscript(self, node): 697 token = next(self.stream) 698 if token.type == 'dot': 699 attr_token = self.stream.current 700 next(self.stream) 701 if attr_token.type == 'name': 702 return nodes.Getattr(node, attr_token.value, 'load', 703 lineno=token.lineno) 704 elif attr_token.type != 'integer': 705 self.fail('expected name or number', attr_token.lineno) 706 arg = nodes.Const(attr_token.value, lineno=attr_token.lineno) 707 return nodes.Getitem(node, arg, 'load', lineno=token.lineno) 708 if token.type == 'lbracket': 709 args = [] 710 while self.stream.current.type != 'rbracket': 711 if args: 712 self.stream.expect('comma') 713 args.append(self.parse_subscribed()) 714 self.stream.expect('rbracket') 715 if len(args) == 1: 716 arg = args[0] 717 else: 718 arg = nodes.Tuple(args, 'load', lineno=token.lineno) 719 return nodes.Getitem(node, arg, 'load', lineno=token.lineno) 720 self.fail('expected subscript expression', self.lineno) 721 722 def parse_subscribed(self): 723 lineno = self.stream.current.lineno 724 725 if self.stream.current.type == 'colon': 726 next(self.stream) 727 args = [None] 728 else: 729 node = self.parse_expression() 730 if self.stream.current.type != 'colon': 731 return node 732 next(self.stream) 733 args = [node] 734 735 if self.stream.current.type == 'colon': 736 args.append(None) 737 elif self.stream.current.type not in ('rbracket', 'comma'): 738 args.append(self.parse_expression()) 739 else: 740 args.append(None) 741 742 if self.stream.current.type == 'colon': 743 next(self.stream) 744 if self.stream.current.type not in ('rbracket', 'comma'): 745 args.append(self.parse_expression()) 746 else: 747 args.append(None) 748 else: 749 args.append(None) 750 751 return nodes.Slice(lineno=lineno, *args) 752 753 def parse_call(self, node): 754 token = self.stream.expect('lparen') 755 args = [] 756 kwargs = [] 757 dyn_args = dyn_kwargs = None 758 require_comma = False 759 760 def ensure(expr): 761 if not expr: 762 self.fail('invalid syntax for function call expression', 763 token.lineno) 764 765 while self.stream.current.type != 'rparen': 766 if require_comma: 767 self.stream.expect('comma') 768 # support for trailing comma 769 if self.stream.current.type == 'rparen': 770 break 771 if self.stream.current.type == 'mul': 772 ensure(dyn_args is None and dyn_kwargs is None) 773 next(self.stream) 774 dyn_args = self.parse_expression() 775 elif self.stream.current.type == 'pow': 776 ensure(dyn_kwargs is None) 777 next(self.stream) 778 dyn_kwargs = self.parse_expression() 779 else: 780 ensure(dyn_args is None and dyn_kwargs is None) 781 if self.stream.current.type == 'name' and \ 782 self.stream.look().type == 'assign': 783 key = self.stream.current.value 784 self.stream.skip(2) 785 value = self.parse_expression() 786 kwargs.append(nodes.Keyword(key, value, 787 lineno=value.lineno)) 788 else: 789 ensure(not kwargs) 790 args.append(self.parse_expression()) 791 792 require_comma = True 793 self.stream.expect('rparen') 794 795 if node is None: 796 return args, kwargs, dyn_args, dyn_kwargs 797 return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs, 798 lineno=token.lineno) 799 800 def parse_filter(self, node, start_inline=False): 801 while self.stream.current.type == 'pipe' or start_inline: 802 if not start_inline: 803 next(self.stream) 804 token = self.stream.expect('name') 805 name = token.value 806 while self.stream.current.type == 'dot': 807 next(self.stream) 808 name += '.' + self.stream.expect('name').value 809 if self.stream.current.type == 'lparen': 810 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None) 811 else: 812 args = [] 813 kwargs = [] 814 dyn_args = dyn_kwargs = None 815 node = nodes.Filter(node, name, args, kwargs, dyn_args, 816 dyn_kwargs, lineno=token.lineno) 817 start_inline = False 818 return node 819 820 def parse_test(self, node): 821 token = next(self.stream) 822 if self.stream.current.test('name:not'): 823 next(self.stream) 824 negated = True 825 else: 826 negated = False 827 name = self.stream.expect('name').value 828 while self.stream.current.type == 'dot': 829 next(self.stream) 830 name += '.' + self.stream.expect('name').value 831 dyn_args = dyn_kwargs = None 832 kwargs = [] 833 if self.stream.current.type == 'lparen': 834 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None) 835 elif (self.stream.current.type in ('name', 'string', 'integer', 836 'float', 'lparen', 'lbracket', 837 'lbrace') and not 838 self.stream.current.test_any('name:else', 'name:or', 839 'name:and')): 840 if self.stream.current.test('name:is'): 841 self.fail('You cannot chain multiple tests with is') 842 args = [self.parse_primary()] 843 else: 844 args = [] 845 node = nodes.Test(node, name, args, kwargs, dyn_args, 846 dyn_kwargs, lineno=token.lineno) 847 if negated: 848 node = nodes.Not(node, lineno=token.lineno) 849 return node 850 851 def subparse(self, end_tokens=None): 852 body = [] 853 data_buffer = [] 854 add_data = data_buffer.append 855 856 if end_tokens is not None: 857 self._end_token_stack.append(end_tokens) 858 859 def flush_data(): 860 if data_buffer: 861 lineno = data_buffer[0].lineno 862 body.append(nodes.Output(data_buffer[:], lineno=lineno)) 863 del data_buffer[:] 864 865 try: 866 while self.stream: 867 token = self.stream.current 868 if token.type == 'data': 869 if token.value: 870 add_data(nodes.TemplateData(token.value, 871 lineno=token.lineno)) 872 next(self.stream) 873 elif token.type == 'variable_begin': 874 next(self.stream) 875 add_data(self.parse_tuple(with_condexpr=True)) 876 self.stream.expect('variable_end') 877 elif token.type == 'block_begin': 878 flush_data() 879 next(self.stream) 880 if end_tokens is not None and \ 881 self.stream.current.test_any(*end_tokens): 882 return body 883 rv = self.parse_statement() 884 if isinstance(rv, list): 885 body.extend(rv) 886 else: 887 body.append(rv) 888 self.stream.expect('block_end') 889 else: 890 raise AssertionError('internal parsing error') 891 892 flush_data() 893 finally: 894 if end_tokens is not None: 895 self._end_token_stack.pop() 896 897 return body 898 899 def parse(self): 900 """Parse the whole template into a `Template` node.""" 901 result = nodes.Template(self.subparse(), lineno=1) 902 result.set_environment(self.environment) 903 return result 904