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