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