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