jinja2.parser

Parse tokens from the lexer into nodes for the compiler.

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

This is the central parsing class Jinja uses. It's passed to extensions and can be used to parse expressions or statements.

Parser( environment: jinja2.environment.Environment, source: str, name: Optional[str] = None, filename: Optional[str] = None, state: Optional[str] = None)
52    def __init__(
53        self,
54        environment: "Environment",
55        source: str,
56        name: t.Optional[str] = None,
57        filename: t.Optional[str] = None,
58        state: t.Optional[str] = None,
59    ) -> None:
60        self.environment = environment
61        self.stream = environment._tokenize(source, name, filename, state)
62        self.name = name
63        self.filename = filename
64        self.closed = False
65        self.extensions: t.Dict[
66            str, t.Callable[["Parser"], t.Union[nodes.Node, t.List[nodes.Node]]]
67        ] = {}
68        for extension in environment.iter_extensions():
69            for tag in extension.tags:
70                self.extensions[tag] = extension.parse
71        self._last_identifier = 0
72        self._tag_stack: t.List[str] = []
73        self._end_token_stack: t.List[t.Tuple[str, ...]] = []
environment
stream
name
filename
closed
extensions: Dict[str, Callable[[Parser], Union[jinja2.nodes.Node, List[jinja2.nodes.Node]]]]
def fail( self, msg: str, lineno: Optional[int] = None, exc: Type[jinja2.exceptions.TemplateSyntaxError] = <class 'jinja2.exceptions.TemplateSyntaxError'>) -> NoReturn:
75    def fail(
76        self,
77        msg: str,
78        lineno: t.Optional[int] = None,
79        exc: t.Type[TemplateSyntaxError] = TemplateSyntaxError,
80    ) -> "te.NoReturn":
81        """Convenience method that raises `exc` with the message, passed
82        line number or last line number as well as the current name and
83        filename.
84        """
85        if lineno is None:
86            lineno = self.stream.current.lineno
87        raise exc(msg, lineno, self.name, self.filename)

Convenience method that raises exc with the message, passed line number or last line number as well as the current name and filename.

def fail_unknown_tag(self, name: str, lineno: Optional[int] = None) -> NoReturn:
129    def fail_unknown_tag(
130        self, name: str, lineno: t.Optional[int] = None
131    ) -> "te.NoReturn":
132        """Called if the parser encounters an unknown tag.  Tries to fail
133        with a human readable error message that could help to identify
134        the problem.
135        """
136        self._fail_ut_eof(name, self._end_token_stack, lineno)

Called if the parser encounters an unknown tag. Tries to fail with a human readable error message that could help to identify the problem.

def fail_eof( self, end_tokens: Optional[Tuple[str, ...]] = None, lineno: Optional[int] = None) -> NoReturn:
138    def fail_eof(
139        self,
140        end_tokens: t.Optional[t.Tuple[str, ...]] = None,
141        lineno: t.Optional[int] = None,
142    ) -> "te.NoReturn":
143        """Like fail_unknown_tag but for end of template situations."""
144        stack = list(self._end_token_stack)
145        if end_tokens is not None:
146            stack.append(end_tokens)
147        self._fail_ut_eof(None, stack, lineno)

Like fail_unknown_tag but for end of template situations.

def is_tuple_end(self, extra_end_rules: Optional[Tuple[str, ...]] = None) -> bool:
149    def is_tuple_end(
150        self, extra_end_rules: t.Optional[t.Tuple[str, ...]] = None
151    ) -> bool:
152        """Are we at the end of a tuple?"""
153        if self.stream.current.type in ("variable_end", "block_end", "rparen"):
154            return True
155        elif extra_end_rules is not None:
156            return self.stream.current.test_any(extra_end_rules)  # type: ignore
157        return False

Are we at the end of a tuple?

def free_identifier(self, lineno: Optional[int] = None) -> jinja2.nodes.InternalName:
159    def free_identifier(self, lineno: t.Optional[int] = None) -> nodes.InternalName:
160        """Return a new free identifier as :class:`~jinja2.nodes.InternalName`."""
161        self._last_identifier += 1
162        rv = object.__new__(nodes.InternalName)
163        nodes.Node.__init__(rv, f"fi{self._last_identifier}", lineno=lineno)
164        return rv

Return a new free identifier as ~jinja2.nodes.InternalName.

def parse_statement(self) -> Union[jinja2.nodes.Node, List[jinja2.nodes.Node]]:
166    def parse_statement(self) -> t.Union[nodes.Node, t.List[nodes.Node]]:
167        """Parse a single statement."""
168        token = self.stream.current
169        if token.type != "name":
170            self.fail("tag name expected", token.lineno)
171        self._tag_stack.append(token.value)
172        pop_tag = True
173        try:
174            if token.value in _statement_keywords:
175                f = getattr(self, f"parse_{self.stream.current.value}")
176                return f()  # type: ignore
177            if token.value == "call":
178                return self.parse_call_block()
179            if token.value == "filter":
180                return self.parse_filter_block()
181            ext = self.extensions.get(token.value)
182            if ext is not None:
183                return ext(self)
184
185            # did not work out, remove the token we pushed by accident
186            # from the stack so that the unknown tag fail function can
187            # produce a proper error message.
188            self._tag_stack.pop()
189            pop_tag = False
190            self.fail_unknown_tag(token.value, token.lineno)
191        finally:
192            if pop_tag:
193                self._tag_stack.pop()

Parse a single statement.

def parse_statements( self, end_tokens: Tuple[str, ...], drop_needle: bool = False) -> List[jinja2.nodes.Node]:
195    def parse_statements(
196        self, end_tokens: t.Tuple[str, ...], drop_needle: bool = False
197    ) -> t.List[nodes.Node]:
198        """Parse multiple statements into a list until one of the end tokens
199        is reached.  This is used to parse the body of statements as it also
200        parses template data if appropriate.  The parser checks first if the
201        current token is a colon and skips it if there is one.  Then it checks
202        for the block end and parses until if one of the `end_tokens` is
203        reached.  Per default the active token in the stream at the end of
204        the call is the matched end token.  If this is not wanted `drop_needle`
205        can be set to `True` and the end token is removed.
206        """
207        # the first token may be a colon for python compatibility
208        self.stream.skip_if("colon")
209
210        # in the future it would be possible to add whole code sections
211        # by adding some sort of end of statement token and parsing those here.
212        self.stream.expect("block_end")
213        result = self.subparse(end_tokens)
214
215        # we reached the end of the template too early, the subparser
216        # does not check for this, so we do that now
217        if self.stream.current.type == "eof":
218            self.fail_eof(end_tokens)
219
220        if drop_needle:
221            next(self.stream)
222        return result

Parse multiple statements into a list until one of the end tokens is reached. This is used to parse the body of statements as it also parses template data if appropriate. The parser checks first if the current token is a colon and skips it if there is one. Then it checks for the block end and parses until if one of the end_tokens is reached. Per default the active token in the stream at the end of the call is the matched end token. If this is not wanted drop_needle can be set to True and the end token is removed.

def parse_set(self) -> Union[jinja2.nodes.Assign, jinja2.nodes.AssignBlock]:
224    def parse_set(self) -> t.Union[nodes.Assign, nodes.AssignBlock]:
225        """Parse an assign statement."""
226        lineno = next(self.stream).lineno
227        target = self.parse_assign_target(with_namespace=True)
228        if self.stream.skip_if("assign"):
229            expr = self.parse_tuple()
230            return nodes.Assign(target, expr, lineno=lineno)
231        filter_node = self.parse_filter(None)
232        body = self.parse_statements(("name:endset",), drop_needle=True)
233        return nodes.AssignBlock(target, filter_node, body, lineno=lineno)

Parse an assign statement.

def parse_for(self) -> jinja2.nodes.For:
235    def parse_for(self) -> nodes.For:
236        """Parse a for loop."""
237        lineno = self.stream.expect("name:for").lineno
238        target = self.parse_assign_target(extra_end_rules=("name:in",))
239        self.stream.expect("name:in")
240        iter = self.parse_tuple(
241            with_condexpr=False, extra_end_rules=("name:recursive",)
242        )
243        test = None
244        if self.stream.skip_if("name:if"):
245            test = self.parse_expression()
246        recursive = self.stream.skip_if("name:recursive")
247        body = self.parse_statements(("name:endfor", "name:else"))
248        if next(self.stream).value == "endfor":
249            else_ = []
250        else:
251            else_ = self.parse_statements(("name:endfor",), drop_needle=True)
252        return nodes.For(target, iter, body, else_, test, recursive, lineno=lineno)

Parse a for loop.

def parse_if(self) -> jinja2.nodes.If:
254    def parse_if(self) -> nodes.If:
255        """Parse an if construct."""
256        node = result = nodes.If(lineno=self.stream.expect("name:if").lineno)
257        while True:
258            node.test = self.parse_tuple(with_condexpr=False)
259            node.body = self.parse_statements(("name:elif", "name:else", "name:endif"))
260            node.elif_ = []
261            node.else_ = []
262            token = next(self.stream)
263            if token.test("name:elif"):
264                node = nodes.If(lineno=self.stream.current.lineno)
265                result.elif_.append(node)
266                continue
267            elif token.test("name:else"):
268                result.else_ = self.parse_statements(("name:endif",), drop_needle=True)
269            break
270        return result

Parse an if construct.

def parse_with(self) -> jinja2.nodes.With:
272    def parse_with(self) -> nodes.With:
273        node = nodes.With(lineno=next(self.stream).lineno)
274        targets: t.List[nodes.Expr] = []
275        values: t.List[nodes.Expr] = []
276        while self.stream.current.type != "block_end":
277            if targets:
278                self.stream.expect("comma")
279            target = self.parse_assign_target()
280            target.set_ctx("param")
281            targets.append(target)
282            self.stream.expect("assign")
283            values.append(self.parse_expression())
284        node.targets = targets
285        node.values = values
286        node.body = self.parse_statements(("name:endwith",), drop_needle=True)
287        return node
def parse_autoescape(self) -> jinja2.nodes.Scope:
289    def parse_autoescape(self) -> nodes.Scope:
290        node = nodes.ScopedEvalContextModifier(lineno=next(self.stream).lineno)
291        node.options = [nodes.Keyword("autoescape", self.parse_expression())]
292        node.body = self.parse_statements(("name:endautoescape",), drop_needle=True)
293        return nodes.Scope([node])
def parse_block(self) -> jinja2.nodes.Block:
295    def parse_block(self) -> nodes.Block:
296        node = nodes.Block(lineno=next(self.stream).lineno)
297        node.name = self.stream.expect("name").value
298        node.scoped = self.stream.skip_if("name:scoped")
299        node.required = self.stream.skip_if("name:required")
300
301        # common problem people encounter when switching from django
302        # to jinja.  we do not support hyphens in block names, so let's
303        # raise a nicer error message in that case.
304        if self.stream.current.type == "sub":
305            self.fail(
306                "Block names in Jinja have to be valid Python identifiers and may not"
307                " contain hyphens, use an underscore instead."
308            )
309
310        node.body = self.parse_statements(("name:endblock",), drop_needle=True)
311
312        # enforce that required blocks only contain whitespace or comments
313        # by asserting that the body, if not empty, is just TemplateData nodes
314        # with whitespace data
315        if node.required:
316            for body_node in node.body:
317                if not isinstance(body_node, nodes.Output) or any(
318                    not isinstance(output_node, nodes.TemplateData)
319                    or not output_node.data.isspace()
320                    for output_node in body_node.nodes
321                ):
322                    self.fail("Required blocks can only contain comments or whitespace")
323
324        self.stream.skip_if("name:" + node.name)
325        return node
def parse_extends(self) -> jinja2.nodes.Extends:
327    def parse_extends(self) -> nodes.Extends:
328        node = nodes.Extends(lineno=next(self.stream).lineno)
329        node.template = self.parse_expression()
330        return node
def parse_import_context(self, node: ~_ImportInclude, default: bool) -> ~_ImportInclude:
332    def parse_import_context(
333        self, node: _ImportInclude, default: bool
334    ) -> _ImportInclude:
335        if self.stream.current.test_any(
336            "name:with", "name:without"
337        ) and self.stream.look().test("name:context"):
338            node.with_context = next(self.stream).value == "with"
339            self.stream.skip()
340        else:
341            node.with_context = default
342        return node
def parse_include(self) -> jinja2.nodes.Include:
344    def parse_include(self) -> nodes.Include:
345        node = nodes.Include(lineno=next(self.stream).lineno)
346        node.template = self.parse_expression()
347        if self.stream.current.test("name:ignore") and self.stream.look().test(
348            "name:missing"
349        ):
350            node.ignore_missing = True
351            self.stream.skip(2)
352        else:
353            node.ignore_missing = False
354        return self.parse_import_context(node, True)
def parse_import(self) -> jinja2.nodes.Import:
356    def parse_import(self) -> nodes.Import:
357        node = nodes.Import(lineno=next(self.stream).lineno)
358        node.template = self.parse_expression()
359        self.stream.expect("name:as")
360        node.target = self.parse_assign_target(name_only=True).name
361        return self.parse_import_context(node, False)
def parse_from(self) -> jinja2.nodes.FromImport:
363    def parse_from(self) -> nodes.FromImport:
364        node = nodes.FromImport(lineno=next(self.stream).lineno)
365        node.template = self.parse_expression()
366        self.stream.expect("name:import")
367        node.names = []
368
369        def parse_context() -> bool:
370            if self.stream.current.value in {
371                "with",
372                "without",
373            } and self.stream.look().test("name:context"):
374                node.with_context = next(self.stream).value == "with"
375                self.stream.skip()
376                return True
377            return False
378
379        while True:
380            if node.names:
381                self.stream.expect("comma")
382            if self.stream.current.type == "name":
383                if parse_context():
384                    break
385                target = self.parse_assign_target(name_only=True)
386                if target.name.startswith("_"):
387                    self.fail(
388                        "names starting with an underline can not be imported",
389                        target.lineno,
390                        exc=TemplateAssertionError,
391                    )
392                if self.stream.skip_if("name:as"):
393                    alias = self.parse_assign_target(name_only=True)
394                    node.names.append((target.name, alias.name))
395                else:
396                    node.names.append(target.name)
397                if parse_context() or self.stream.current.type != "comma":
398                    break
399            else:
400                self.stream.expect("name")
401        if not hasattr(node, "with_context"):
402            node.with_context = False
403        return node
def parse_signature(self, node: ~_MacroCall) -> None:
405    def parse_signature(self, node: _MacroCall) -> None:
406        args = node.args = []
407        defaults = node.defaults = []
408        self.stream.expect("lparen")
409        while self.stream.current.type != "rparen":
410            if args:
411                self.stream.expect("comma")
412            arg = self.parse_assign_target(name_only=True)
413            arg.set_ctx("param")
414            if self.stream.skip_if("assign"):
415                defaults.append(self.parse_expression())
416            elif defaults:
417                self.fail("non-default argument follows default argument")
418            args.append(arg)
419        self.stream.expect("rparen")
def parse_call_block(self) -> jinja2.nodes.CallBlock:
421    def parse_call_block(self) -> nodes.CallBlock:
422        node = nodes.CallBlock(lineno=next(self.stream).lineno)
423        if self.stream.current.type == "lparen":
424            self.parse_signature(node)
425        else:
426            node.args = []
427            node.defaults = []
428
429        call_node = self.parse_expression()
430        if not isinstance(call_node, nodes.Call):
431            self.fail("expected call", node.lineno)
432        node.call = call_node
433        node.body = self.parse_statements(("name:endcall",), drop_needle=True)
434        return node
def parse_filter_block(self) -> jinja2.nodes.FilterBlock:
436    def parse_filter_block(self) -> nodes.FilterBlock:
437        node = nodes.FilterBlock(lineno=next(self.stream).lineno)
438        node.filter = self.parse_filter(None, start_inline=True)  # type: ignore
439        node.body = self.parse_statements(("name:endfilter",), drop_needle=True)
440        return node
def parse_macro(self) -> jinja2.nodes.Macro:
442    def parse_macro(self) -> nodes.Macro:
443        node = nodes.Macro(lineno=next(self.stream).lineno)
444        node.name = self.parse_assign_target(name_only=True).name
445        self.parse_signature(node)
446        node.body = self.parse_statements(("name:endmacro",), drop_needle=True)
447        return node
def parse_print(self) -> jinja2.nodes.Output:
449    def parse_print(self) -> nodes.Output:
450        node = nodes.Output(lineno=next(self.stream).lineno)
451        node.nodes = []
452        while self.stream.current.type != "block_end":
453            if node.nodes:
454                self.stream.expect("comma")
455            node.nodes.append(self.parse_expression())
456        return node
def parse_assign_target( self, with_tuple: bool = True, name_only: bool = False, extra_end_rules: Optional[Tuple[str, ...]] = None, with_namespace: bool = False) -> Union[jinja2.nodes.NSRef, jinja2.nodes.Name, jinja2.nodes.Tuple]:
474    def parse_assign_target(
475        self,
476        with_tuple: bool = True,
477        name_only: bool = False,
478        extra_end_rules: t.Optional[t.Tuple[str, ...]] = None,
479        with_namespace: bool = False,
480    ) -> t.Union[nodes.NSRef, nodes.Name, nodes.Tuple]:
481        """Parse an assignment target.  As Jinja allows assignments to
482        tuples, this function can parse all allowed assignment targets.  Per
483        default assignments to tuples are parsed, that can be disable however
484        by setting `with_tuple` to `False`.  If only assignments to names are
485        wanted `name_only` can be set to `True`.  The `extra_end_rules`
486        parameter is forwarded to the tuple parsing function.  If
487        `with_namespace` is enabled, a namespace assignment may be parsed.
488        """
489        target: nodes.Expr
490
491        if with_namespace and self.stream.look().type == "dot":
492            token = self.stream.expect("name")
493            next(self.stream)  # dot
494            attr = self.stream.expect("name")
495            target = nodes.NSRef(token.value, attr.value, lineno=token.lineno)
496        elif name_only:
497            token = self.stream.expect("name")
498            target = nodes.Name(token.value, "store", lineno=token.lineno)
499        else:
500            if with_tuple:
501                target = self.parse_tuple(
502                    simplified=True, extra_end_rules=extra_end_rules
503                )
504            else:
505                target = self.parse_primary()
506
507            target.set_ctx("store")
508
509        if not target.can_assign():
510            self.fail(
511                f"can't assign to {type(target).__name__.lower()!r}", target.lineno
512            )
513
514        return target  # type: ignore

Parse an assignment target. As Jinja allows assignments to tuples, this function can parse all allowed assignment targets. Per default assignments to tuples are parsed, that can be disable however by setting with_tuple to False. If only assignments to names are wanted name_only can be set to True. The extra_end_rules parameter is forwarded to the tuple parsing function. If with_namespace is enabled, a namespace assignment may be parsed.

def parse_expression(self, with_condexpr: bool = True) -> jinja2.nodes.Expr:
516    def parse_expression(self, with_condexpr: bool = True) -> nodes.Expr:
517        """Parse an expression.  Per default all expressions are parsed, if
518        the optional `with_condexpr` parameter is set to `False` conditional
519        expressions are not parsed.
520        """
521        if with_condexpr:
522            return self.parse_condexpr()
523        return self.parse_or()

Parse an expression. Per default all expressions are parsed, if the optional with_condexpr parameter is set to False conditional expressions are not parsed.

def parse_condexpr(self) -> jinja2.nodes.Expr:
525    def parse_condexpr(self) -> nodes.Expr:
526        lineno = self.stream.current.lineno
527        expr1 = self.parse_or()
528        expr3: t.Optional[nodes.Expr]
529
530        while self.stream.skip_if("name:if"):
531            expr2 = self.parse_or()
532            if self.stream.skip_if("name:else"):
533                expr3 = self.parse_condexpr()
534            else:
535                expr3 = None
536            expr1 = nodes.CondExpr(expr2, expr1, expr3, lineno=lineno)
537            lineno = self.stream.current.lineno
538        return expr1
def parse_or(self) -> jinja2.nodes.Expr:
540    def parse_or(self) -> nodes.Expr:
541        lineno = self.stream.current.lineno
542        left = self.parse_and()
543        while self.stream.skip_if("name:or"):
544            right = self.parse_and()
545            left = nodes.Or(left, right, lineno=lineno)
546            lineno = self.stream.current.lineno
547        return left
def parse_and(self) -> jinja2.nodes.Expr:
549    def parse_and(self) -> nodes.Expr:
550        lineno = self.stream.current.lineno
551        left = self.parse_not()
552        while self.stream.skip_if("name:and"):
553            right = self.parse_not()
554            left = nodes.And(left, right, lineno=lineno)
555            lineno = self.stream.current.lineno
556        return left
def parse_not(self) -> jinja2.nodes.Expr:
558    def parse_not(self) -> nodes.Expr:
559        if self.stream.current.test("name:not"):
560            lineno = next(self.stream).lineno
561            return nodes.Not(self.parse_not(), lineno=lineno)
562        return self.parse_compare()
def parse_compare(self) -> jinja2.nodes.Expr:
564    def parse_compare(self) -> nodes.Expr:
565        lineno = self.stream.current.lineno
566        expr = self.parse_math1()
567        ops = []
568        while True:
569            token_type = self.stream.current.type
570            if token_type in _compare_operators:
571                next(self.stream)
572                ops.append(nodes.Operand(token_type, self.parse_math1()))
573            elif self.stream.skip_if("name:in"):
574                ops.append(nodes.Operand("in", self.parse_math1()))
575            elif self.stream.current.test("name:not") and self.stream.look().test(
576                "name:in"
577            ):
578                self.stream.skip(2)
579                ops.append(nodes.Operand("notin", self.parse_math1()))
580            else:
581                break
582            lineno = self.stream.current.lineno
583        if not ops:
584            return expr
585        return nodes.Compare(expr, ops, lineno=lineno)
def parse_math1(self) -> jinja2.nodes.Expr:
587    def parse_math1(self) -> nodes.Expr:
588        lineno = self.stream.current.lineno
589        left = self.parse_concat()
590        while self.stream.current.type in ("add", "sub"):
591            cls = _math_nodes[self.stream.current.type]
592            next(self.stream)
593            right = self.parse_concat()
594            left = cls(left, right, lineno=lineno)
595            lineno = self.stream.current.lineno
596        return left
def parse_concat(self) -> jinja2.nodes.Expr:
598    def parse_concat(self) -> nodes.Expr:
599        lineno = self.stream.current.lineno
600        args = [self.parse_math2()]
601        while self.stream.current.type == "tilde":
602            next(self.stream)
603            args.append(self.parse_math2())
604        if len(args) == 1:
605            return args[0]
606        return nodes.Concat(args, lineno=lineno)
def parse_math2(self) -> jinja2.nodes.Expr:
608    def parse_math2(self) -> nodes.Expr:
609        lineno = self.stream.current.lineno
610        left = self.parse_pow()
611        while self.stream.current.type in ("mul", "div", "floordiv", "mod"):
612            cls = _math_nodes[self.stream.current.type]
613            next(self.stream)
614            right = self.parse_pow()
615            left = cls(left, right, lineno=lineno)
616            lineno = self.stream.current.lineno
617        return left
def parse_pow(self) -> jinja2.nodes.Expr:
619    def parse_pow(self) -> nodes.Expr:
620        lineno = self.stream.current.lineno
621        left = self.parse_unary()
622        while self.stream.current.type == "pow":
623            next(self.stream)
624            right = self.parse_unary()
625            left = nodes.Pow(left, right, lineno=lineno)
626            lineno = self.stream.current.lineno
627        return left
def parse_unary(self, with_filter: bool = True) -> jinja2.nodes.Expr:
629    def parse_unary(self, with_filter: bool = True) -> nodes.Expr:
630        token_type = self.stream.current.type
631        lineno = self.stream.current.lineno
632        node: nodes.Expr
633
634        if token_type == "sub":
635            next(self.stream)
636            node = nodes.Neg(self.parse_unary(False), lineno=lineno)
637        elif token_type == "add":
638            next(self.stream)
639            node = nodes.Pos(self.parse_unary(False), lineno=lineno)
640        else:
641            node = self.parse_primary()
642        node = self.parse_postfix(node)
643        if with_filter:
644            node = self.parse_filter_expr(node)
645        return node
def parse_primary(self) -> jinja2.nodes.Expr:
647    def parse_primary(self) -> nodes.Expr:
648        token = self.stream.current
649        node: nodes.Expr
650        if token.type == "name":
651            if token.value in ("true", "false", "True", "False"):
652                node = nodes.Const(token.value in ("true", "True"), lineno=token.lineno)
653            elif token.value in ("none", "None"):
654                node = nodes.Const(None, lineno=token.lineno)
655            else:
656                node = nodes.Name(token.value, "load", lineno=token.lineno)
657            next(self.stream)
658        elif token.type == "string":
659            next(self.stream)
660            buf = [token.value]
661            lineno = token.lineno
662            while self.stream.current.type == "string":
663                buf.append(self.stream.current.value)
664                next(self.stream)
665            node = nodes.Const("".join(buf), lineno=lineno)
666        elif token.type in ("integer", "float"):
667            next(self.stream)
668            node = nodes.Const(token.value, lineno=token.lineno)
669        elif token.type == "lparen":
670            next(self.stream)
671            node = self.parse_tuple(explicit_parentheses=True)
672            self.stream.expect("rparen")
673        elif token.type == "lbracket":
674            node = self.parse_list()
675        elif token.type == "lbrace":
676            node = self.parse_dict()
677        else:
678            self.fail(f"unexpected {describe_token(token)!r}", token.lineno)
679        return node
def parse_tuple( self, simplified: bool = False, with_condexpr: bool = True, extra_end_rules: Optional[Tuple[str, ...]] = None, explicit_parentheses: bool = False) -> Union[jinja2.nodes.Tuple, jinja2.nodes.Expr]:
681    def parse_tuple(
682        self,
683        simplified: bool = False,
684        with_condexpr: bool = True,
685        extra_end_rules: t.Optional[t.Tuple[str, ...]] = None,
686        explicit_parentheses: bool = False,
687    ) -> t.Union[nodes.Tuple, nodes.Expr]:
688        """Works like `parse_expression` but if multiple expressions are
689        delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created.
690        This method could also return a regular expression instead of a tuple
691        if no commas where found.
692
693        The default parsing mode is a full tuple.  If `simplified` is `True`
694        only names and literals are parsed.  The `no_condexpr` parameter is
695        forwarded to :meth:`parse_expression`.
696
697        Because tuples do not require delimiters and may end in a bogus comma
698        an extra hint is needed that marks the end of a tuple.  For example
699        for loops support tuples between `for` and `in`.  In that case the
700        `extra_end_rules` is set to ``['name:in']``.
701
702        `explicit_parentheses` is true if the parsing was triggered by an
703        expression in parentheses.  This is used to figure out if an empty
704        tuple is a valid expression or not.
705        """
706        lineno = self.stream.current.lineno
707        if simplified:
708            parse = self.parse_primary
709        elif with_condexpr:
710            parse = self.parse_expression
711        else:
712
713            def parse() -> nodes.Expr:
714                return self.parse_expression(with_condexpr=False)
715
716        args: t.List[nodes.Expr] = []
717        is_tuple = False
718
719        while True:
720            if args:
721                self.stream.expect("comma")
722            if self.is_tuple_end(extra_end_rules):
723                break
724            args.append(parse())
725            if self.stream.current.type == "comma":
726                is_tuple = True
727            else:
728                break
729            lineno = self.stream.current.lineno
730
731        if not is_tuple:
732            if args:
733                return args[0]
734
735            # if we don't have explicit parentheses, an empty tuple is
736            # not a valid expression.  This would mean nothing (literally
737            # nothing) in the spot of an expression would be an empty
738            # tuple.
739            if not explicit_parentheses:
740                self.fail(
741                    "Expected an expression,"
742                    f" got {describe_token(self.stream.current)!r}"
743                )
744
745        return nodes.Tuple(args, "load", lineno=lineno)

Works like parse_expression but if multiple expressions are delimited by a comma a ~jinja2.nodes.Tuple node is created. This method could also return a regular expression instead of a tuple if no commas where found.

The default parsing mode is a full tuple. If simplified is True only names and literals are parsed. The no_condexpr parameter is forwarded to parse_expression().

Because tuples do not require delimiters and may end in a bogus comma an extra hint is needed that marks the end of a tuple. For example for loops support tuples between for and in. In that case the extra_end_rules is set to ['name:in'].

explicit_parentheses is true if the parsing was triggered by an expression in parentheses. This is used to figure out if an empty tuple is a valid expression or not.

def parse_list(self) -> jinja2.nodes.List:
747    def parse_list(self) -> nodes.List:
748        token = self.stream.expect("lbracket")
749        items: t.List[nodes.Expr] = []
750        while self.stream.current.type != "rbracket":
751            if items:
752                self.stream.expect("comma")
753            if self.stream.current.type == "rbracket":
754                break
755            items.append(self.parse_expression())
756        self.stream.expect("rbracket")
757        return nodes.List(items, lineno=token.lineno)
def parse_dict(self) -> jinja2.nodes.Dict:
759    def parse_dict(self) -> nodes.Dict:
760        token = self.stream.expect("lbrace")
761        items: t.List[nodes.Pair] = []
762        while self.stream.current.type != "rbrace":
763            if items:
764                self.stream.expect("comma")
765            if self.stream.current.type == "rbrace":
766                break
767            key = self.parse_expression()
768            self.stream.expect("colon")
769            value = self.parse_expression()
770            items.append(nodes.Pair(key, value, lineno=key.lineno))
771        self.stream.expect("rbrace")
772        return nodes.Dict(items, lineno=token.lineno)
def parse_postfix(self, node: jinja2.nodes.Expr) -> jinja2.nodes.Expr:
774    def parse_postfix(self, node: nodes.Expr) -> nodes.Expr:
775        while True:
776            token_type = self.stream.current.type
777            if token_type == "dot" or token_type == "lbracket":
778                node = self.parse_subscript(node)
779            # calls are valid both after postfix expressions (getattr
780            # and getitem) as well as filters and tests
781            elif token_type == "lparen":
782                node = self.parse_call(node)
783            else:
784                break
785        return node
def parse_filter_expr(self, node: jinja2.nodes.Expr) -> jinja2.nodes.Expr:
787    def parse_filter_expr(self, node: nodes.Expr) -> nodes.Expr:
788        while True:
789            token_type = self.stream.current.type
790            if token_type == "pipe":
791                node = self.parse_filter(node)  # type: ignore
792            elif token_type == "name" and self.stream.current.value == "is":
793                node = self.parse_test(node)
794            # calls are valid both after postfix expressions (getattr
795            # and getitem) as well as filters and tests
796            elif token_type == "lparen":
797                node = self.parse_call(node)
798            else:
799                break
800        return node
def parse_subscript( self, node: jinja2.nodes.Expr) -> Union[jinja2.nodes.Getattr, jinja2.nodes.Getitem]:
802    def parse_subscript(
803        self, node: nodes.Expr
804    ) -> t.Union[nodes.Getattr, nodes.Getitem]:
805        token = next(self.stream)
806        arg: nodes.Expr
807
808        if token.type == "dot":
809            attr_token = self.stream.current
810            next(self.stream)
811            if attr_token.type == "name":
812                return nodes.Getattr(
813                    node, attr_token.value, "load", lineno=token.lineno
814                )
815            elif attr_token.type != "integer":
816                self.fail("expected name or number", attr_token.lineno)
817            arg = nodes.Const(attr_token.value, lineno=attr_token.lineno)
818            return nodes.Getitem(node, arg, "load", lineno=token.lineno)
819        if token.type == "lbracket":
820            args: t.List[nodes.Expr] = []
821            while self.stream.current.type != "rbracket":
822                if args:
823                    self.stream.expect("comma")
824                args.append(self.parse_subscribed())
825            self.stream.expect("rbracket")
826            if len(args) == 1:
827                arg = args[0]
828            else:
829                arg = nodes.Tuple(args, "load", lineno=token.lineno)
830            return nodes.Getitem(node, arg, "load", lineno=token.lineno)
831        self.fail("expected subscript expression", token.lineno)
def parse_subscribed(self) -> jinja2.nodes.Expr:
833    def parse_subscribed(self) -> nodes.Expr:
834        lineno = self.stream.current.lineno
835        args: t.List[t.Optional[nodes.Expr]]
836
837        if self.stream.current.type == "colon":
838            next(self.stream)
839            args = [None]
840        else:
841            node = self.parse_expression()
842            if self.stream.current.type != "colon":
843                return node
844            next(self.stream)
845            args = [node]
846
847        if self.stream.current.type == "colon":
848            args.append(None)
849        elif self.stream.current.type not in ("rbracket", "comma"):
850            args.append(self.parse_expression())
851        else:
852            args.append(None)
853
854        if self.stream.current.type == "colon":
855            next(self.stream)
856            if self.stream.current.type not in ("rbracket", "comma"):
857                args.append(self.parse_expression())
858            else:
859                args.append(None)
860        else:
861            args.append(None)
862
863        return nodes.Slice(lineno=lineno, *args)  # noqa: B026
def parse_call_args(self) -> Tuple:
865    def parse_call_args(self) -> t.Tuple:
866        token = self.stream.expect("lparen")
867        args = []
868        kwargs = []
869        dyn_args = None
870        dyn_kwargs = None
871        require_comma = False
872
873        def ensure(expr: bool) -> None:
874            if not expr:
875                self.fail("invalid syntax for function call expression", token.lineno)
876
877        while self.stream.current.type != "rparen":
878            if require_comma:
879                self.stream.expect("comma")
880
881                # support for trailing comma
882                if self.stream.current.type == "rparen":
883                    break
884
885            if self.stream.current.type == "mul":
886                ensure(dyn_args is None and dyn_kwargs is None)
887                next(self.stream)
888                dyn_args = self.parse_expression()
889            elif self.stream.current.type == "pow":
890                ensure(dyn_kwargs is None)
891                next(self.stream)
892                dyn_kwargs = self.parse_expression()
893            else:
894                if (
895                    self.stream.current.type == "name"
896                    and self.stream.look().type == "assign"
897                ):
898                    # Parsing a kwarg
899                    ensure(dyn_kwargs is None)
900                    key = self.stream.current.value
901                    self.stream.skip(2)
902                    value = self.parse_expression()
903                    kwargs.append(nodes.Keyword(key, value, lineno=value.lineno))
904                else:
905                    # Parsing an arg
906                    ensure(dyn_args is None and dyn_kwargs is None and not kwargs)
907                    args.append(self.parse_expression())
908
909            require_comma = True
910
911        self.stream.expect("rparen")
912        return args, kwargs, dyn_args, dyn_kwargs
def parse_call(self, node: jinja2.nodes.Expr) -> jinja2.nodes.Call:
914    def parse_call(self, node: nodes.Expr) -> nodes.Call:
915        # The lparen will be expected in parse_call_args, but the lineno
916        # needs to be recorded before the stream is advanced.
917        token = self.stream.current
918        args, kwargs, dyn_args, dyn_kwargs = self.parse_call_args()
919        return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno)
def parse_filter( self, node: Optional[jinja2.nodes.Expr], start_inline: bool = False) -> Optional[jinja2.nodes.Expr]:
921    def parse_filter(
922        self, node: t.Optional[nodes.Expr], start_inline: bool = False
923    ) -> t.Optional[nodes.Expr]:
924        while self.stream.current.type == "pipe" or start_inline:
925            if not start_inline:
926                next(self.stream)
927            token = self.stream.expect("name")
928            name = token.value
929            while self.stream.current.type == "dot":
930                next(self.stream)
931                name += "." + self.stream.expect("name").value
932            if self.stream.current.type == "lparen":
933                args, kwargs, dyn_args, dyn_kwargs = self.parse_call_args()
934            else:
935                args = []
936                kwargs = []
937                dyn_args = dyn_kwargs = None
938            node = nodes.Filter(
939                node, name, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno
940            )
941            start_inline = False
942        return node
def parse_test(self, node: jinja2.nodes.Expr) -> jinja2.nodes.Expr:
944    def parse_test(self, node: nodes.Expr) -> nodes.Expr:
945        token = next(self.stream)
946        if self.stream.current.test("name:not"):
947            next(self.stream)
948            negated = True
949        else:
950            negated = False
951        name = self.stream.expect("name").value
952        while self.stream.current.type == "dot":
953            next(self.stream)
954            name += "." + self.stream.expect("name").value
955        dyn_args = dyn_kwargs = None
956        kwargs = []
957        if self.stream.current.type == "lparen":
958            args, kwargs, dyn_args, dyn_kwargs = self.parse_call_args()
959        elif self.stream.current.type in {
960            "name",
961            "string",
962            "integer",
963            "float",
964            "lparen",
965            "lbracket",
966            "lbrace",
967        } and not self.stream.current.test_any("name:else", "name:or", "name:and"):
968            if self.stream.current.test("name:is"):
969                self.fail("You cannot chain multiple tests with is")
970            arg_node = self.parse_primary()
971            arg_node = self.parse_postfix(arg_node)
972            args = [arg_node]
973        else:
974            args = []
975        node = nodes.Test(
976            node, name, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno
977        )
978        if negated:
979            node = nodes.Not(node, lineno=token.lineno)
980        return node
def subparse( self, end_tokens: Optional[Tuple[str, ...]] = None) -> List[jinja2.nodes.Node]:
 982    def subparse(
 983        self, end_tokens: t.Optional[t.Tuple[str, ...]] = None
 984    ) -> t.List[nodes.Node]:
 985        body: t.List[nodes.Node] = []
 986        data_buffer: t.List[nodes.Node] = []
 987        add_data = data_buffer.append
 988
 989        if end_tokens is not None:
 990            self._end_token_stack.append(end_tokens)
 991
 992        def flush_data() -> None:
 993            if data_buffer:
 994                lineno = data_buffer[0].lineno
 995                body.append(nodes.Output(data_buffer[:], lineno=lineno))
 996                del data_buffer[:]
 997
 998        try:
 999            while self.stream:
1000                token = self.stream.current
1001                if token.type == "data":
1002                    if token.value:
1003                        add_data(nodes.TemplateData(token.value, lineno=token.lineno))
1004                    next(self.stream)
1005                elif token.type == "variable_begin":
1006                    next(self.stream)
1007                    add_data(self.parse_tuple(with_condexpr=True))
1008                    self.stream.expect("variable_end")
1009                elif token.type == "block_begin":
1010                    flush_data()
1011                    next(self.stream)
1012                    if end_tokens is not None and self.stream.current.test_any(
1013                        *end_tokens
1014                    ):
1015                        return body
1016                    rv = self.parse_statement()
1017                    if isinstance(rv, list):
1018                        body.extend(rv)
1019                    else:
1020                        body.append(rv)
1021                    self.stream.expect("block_end")
1022                else:
1023                    raise AssertionError("internal parsing error")
1024
1025            flush_data()
1026        finally:
1027            if end_tokens is not None:
1028                self._end_token_stack.pop()
1029        return body
def parse(self) -> jinja2.nodes.Template:
1031    def parse(self) -> nodes.Template:
1032        """Parse the whole template into a `Template` node."""
1033        result = nodes.Template(self.subparse(), lineno=1)
1034        result.set_environment(self.environment)
1035        return result

Parse the whole template into a Template node.