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