• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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