jinja2.parser

Parse tokens from the lexer into nodes for the compiler.

   1"""Parse tokens from the lexer into nodes for the compiler."""
   2
   3import typing
   4import typing as t
   5
   6from . import nodes
   7from .exceptions import TemplateAssertionError
   8from .exceptions import TemplateSyntaxError
   9from .lexer import describe_token
  10from .lexer import describe_token_expr
  11
  12if t.TYPE_CHECKING:
  13    import typing_extensions as te
  14
  15    from .environment import Environment
  16
  17_ImportInclude = t.TypeVar("_ImportInclude", nodes.Import, nodes.Include)
  18_MacroCall = t.TypeVar("_MacroCall", nodes.Macro, nodes.CallBlock)
  19
  20_statement_keywords = frozenset(
  21    [
  22        "for",
  23        "if",
  24        "block",
  25        "extends",
  26        "print",
  27        "macro",
  28        "include",
  29        "from",
  30        "import",
  31        "set",
  32        "with",
  33        "autoescape",
  34    ]
  35)
  36_compare_operators = frozenset(["eq", "ne", "lt", "lteq", "gt", "gteq"])
  37
  38_math_nodes: t.Dict[str, t.Type[nodes.Expr]] = {
  39    "add": nodes.Add,
  40    "sub": nodes.Sub,
  41    "mul": nodes.Mul,
  42    "div": nodes.Div,
  43    "floordiv": nodes.FloorDiv,
  44    "mod": nodes.Mod,
  45}
  46
  47
  48class Parser:
  49    """This is the central parsing class Jinja uses.  It's passed to
  50    extensions and can be used to parse expressions or statements.
  51    """
  52
  53    def __init__(
  54        self,
  55        environment: "Environment",
  56        source: str,
  57        name: t.Optional[str] = None,
  58        filename: t.Optional[str] = None,
  59        state: t.Optional[str] = None,
  60    ) -> None:
  61        self.environment = environment
  62        self.stream = environment._tokenize(source, name, filename, state)
  63        self.name = name
  64        self.filename = filename
  65        self.closed = False
  66        self.extensions: t.Dict[
  67            str, t.Callable[["Parser"], t.Union[nodes.Node, t.List[nodes.Node]]]
  68        ] = {}
  69        for extension in environment.iter_extensions():
  70            for tag in extension.tags:
  71                self.extensions[tag] = extension.parse
  72        self._last_identifier = 0
  73        self._tag_stack: t.List[str] = []
  74        self._end_token_stack: t.List[t.Tuple[str, ...]] = []
  75
  76    def fail(
  77        self,
  78        msg: str,
  79        lineno: t.Optional[int] = None,
  80        exc: t.Type[TemplateSyntaxError] = TemplateSyntaxError,
  81    ) -> "te.NoReturn":
  82        """Convenience method that raises `exc` with the message, passed
  83        line number or last line number as well as the current name and
  84        filename.
  85        """
  86        if lineno is None:
  87            lineno = self.stream.current.lineno
  88        raise exc(msg, lineno, self.name, self.filename)
  89
  90    def _fail_ut_eof(
  91        self,
  92        name: t.Optional[str],
  93        end_token_stack: t.List[t.Tuple[str, ...]],
  94        lineno: t.Optional[int],
  95    ) -> "te.NoReturn":
  96        expected: t.Set[str] = set()
  97        for exprs in end_token_stack:
  98            expected.update(map(describe_token_expr, exprs))
  99        if end_token_stack:
 100            currently_looking: t.Optional[str] = " or ".join(
 101                map(repr, map(describe_token_expr, end_token_stack[-1]))
 102            )
 103        else:
 104            currently_looking = None
 105
 106        if name is None:
 107            message = ["Unexpected end of template."]
 108        else:
 109            message = [f"Encountered unknown tag {name!r}."]
 110
 111        if currently_looking:
 112            if name is not None and name in expected:
 113                message.append(
 114                    "You probably made a nesting mistake. Jinja is expecting this tag,"
 115                    f" but currently looking for {currently_looking}."
 116                )
 117            else:
 118                message.append(
 119                    f"Jinja was looking for the following tags: {currently_looking}."
 120                )
 121
 122        if self._tag_stack:
 123            message.append(
 124                "The innermost block that needs to be closed is"
 125                f" {self._tag_stack[-1]!r}."
 126            )
 127
 128        self.fail(" ".join(message), lineno)
 129
 130    def fail_unknown_tag(
 131        self, name: str, lineno: t.Optional[int] = None
 132    ) -> "te.NoReturn":
 133        """Called if the parser encounters an unknown tag.  Tries to fail
 134        with a human readable error message that could help to identify
 135        the problem.
 136        """
 137        self._fail_ut_eof(name, self._end_token_stack, lineno)
 138
 139    def fail_eof(
 140        self,
 141        end_tokens: t.Optional[t.Tuple[str, ...]] = None,
 142        lineno: t.Optional[int] = None,
 143    ) -> "te.NoReturn":
 144        """Like fail_unknown_tag but for end of template situations."""
 145        stack = list(self._end_token_stack)
 146        if end_tokens is not None:
 147            stack.append(end_tokens)
 148        self._fail_ut_eof(None, stack, lineno)
 149
 150    def is_tuple_end(
 151        self, extra_end_rules: t.Optional[t.Tuple[str, ...]] = None
 152    ) -> bool:
 153        """Are we at the end of a tuple?"""
 154        if self.stream.current.type in ("variable_end", "block_end", "rparen"):
 155            return True
 156        elif extra_end_rules is not None:
 157            return self.stream.current.test_any(extra_end_rules)  # type: ignore
 158        return False
 159
 160    def free_identifier(self, lineno: t.Optional[int] = None) -> nodes.InternalName:
 161        """Return a new free identifier as :class:`~jinja2.nodes.InternalName`."""
 162        self._last_identifier += 1
 163        rv = object.__new__(nodes.InternalName)
 164        nodes.Node.__init__(rv, f"fi{self._last_identifier}", lineno=lineno)
 165        return rv
 166
 167    def parse_statement(self) -> t.Union[nodes.Node, t.List[nodes.Node]]:
 168        """Parse a single statement."""
 169        token = self.stream.current
 170        if token.type != "name":
 171            self.fail("tag name expected", token.lineno)
 172        self._tag_stack.append(token.value)
 173        pop_tag = True
 174        try:
 175            if token.value in _statement_keywords:
 176                f = getattr(self, f"parse_{self.stream.current.value}")
 177                return f()  # type: ignore
 178            if token.value == "call":
 179                return self.parse_call_block()
 180            if token.value == "filter":
 181                return self.parse_filter_block()
 182            ext = self.extensions.get(token.value)
 183            if ext is not None:
 184                return ext(self)
 185
 186            # did not work out, remove the token we pushed by accident
 187            # from the stack so that the unknown tag fail function can
 188            # produce a proper error message.
 189            self._tag_stack.pop()
 190            pop_tag = False
 191            self.fail_unknown_tag(token.value, token.lineno)
 192        finally:
 193            if pop_tag:
 194                self._tag_stack.pop()
 195
 196    def parse_statements(
 197        self, end_tokens: t.Tuple[str, ...], drop_needle: bool = False
 198    ) -> t.List[nodes.Node]:
 199        """Parse multiple statements into a list until one of the end tokens
 200        is reached.  This is used to parse the body of statements as it also
 201        parses template data if appropriate.  The parser checks first if the
 202        current token is a colon and skips it if there is one.  Then it checks
 203        for the block end and parses until if one of the `end_tokens` is
 204        reached.  Per default the active token in the stream at the end of
 205        the call is the matched end token.  If this is not wanted `drop_needle`
 206        can be set to `True` and the end token is removed.
 207        """
 208        # the first token may be a colon for python compatibility
 209        self.stream.skip_if("colon")
 210
 211        # in the future it would be possible to add whole code sections
 212        # by adding some sort of end of statement token and parsing those here.
 213        self.stream.expect("block_end")
 214        result = self.subparse(end_tokens)
 215
 216        # we reached the end of the template too early, the subparser
 217        # does not check for this, so we do that now
 218        if self.stream.current.type == "eof":
 219            self.fail_eof(end_tokens)
 220
 221        if drop_needle:
 222            next(self.stream)
 223        return result
 224
 225    def parse_set(self) -> t.Union[nodes.Assign, nodes.AssignBlock]:
 226        """Parse an assign statement."""
 227        lineno = next(self.stream).lineno
 228        target = self.parse_assign_target(with_namespace=True)
 229        if self.stream.skip_if("assign"):
 230            expr = self.parse_tuple()
 231            return nodes.Assign(target, expr, lineno=lineno)
 232        filter_node = self.parse_filter(None)
 233        body = self.parse_statements(("name:endset",), drop_needle=True)
 234        return nodes.AssignBlock(target, filter_node, body, lineno=lineno)
 235
 236    def parse_for(self) -> nodes.For:
 237        """Parse a for loop."""
 238        lineno = self.stream.expect("name:for").lineno
 239        target = self.parse_assign_target(extra_end_rules=("name:in",))
 240        self.stream.expect("name:in")
 241        iter = self.parse_tuple(
 242            with_condexpr=False, extra_end_rules=("name:recursive",)
 243        )
 244        test = None
 245        if self.stream.skip_if("name:if"):
 246            test = self.parse_expression()
 247        recursive = self.stream.skip_if("name:recursive")
 248        body = self.parse_statements(("name:endfor", "name:else"))
 249        if next(self.stream).value == "endfor":
 250            else_ = []
 251        else:
 252            else_ = self.parse_statements(("name:endfor",), drop_needle=True)
 253        return nodes.For(target, iter, body, else_, test, recursive, lineno=lineno)
 254
 255    def parse_if(self) -> nodes.If:
 256        """Parse an if construct."""
 257        node = result = nodes.If(lineno=self.stream.expect("name:if").lineno)
 258        while True:
 259            node.test = self.parse_tuple(with_condexpr=False)
 260            node.body = self.parse_statements(("name:elif", "name:else", "name:endif"))
 261            node.elif_ = []
 262            node.else_ = []
 263            token = next(self.stream)
 264            if token.test("name:elif"):
 265                node = nodes.If(lineno=self.stream.current.lineno)
 266                result.elif_.append(node)
 267                continue
 268            elif token.test("name:else"):
 269                result.else_ = self.parse_statements(("name:endif",), drop_needle=True)
 270            break
 271        return result
 272
 273    def parse_with(self) -> nodes.With:
 274        node = nodes.With(lineno=next(self.stream).lineno)
 275        targets: t.List[nodes.Expr] = []
 276        values: t.List[nodes.Expr] = []
 277        while self.stream.current.type != "block_end":
 278            if targets:
 279                self.stream.expect("comma")
 280            target = self.parse_assign_target()
 281            target.set_ctx("param")
 282            targets.append(target)
 283            self.stream.expect("assign")
 284            values.append(self.parse_expression())
 285        node.targets = targets
 286        node.values = values
 287        node.body = self.parse_statements(("name:endwith",), drop_needle=True)
 288        return node
 289
 290    def parse_autoescape(self) -> nodes.Scope:
 291        node = nodes.ScopedEvalContextModifier(lineno=next(self.stream).lineno)
 292        node.options = [nodes.Keyword("autoescape", self.parse_expression())]
 293        node.body = self.parse_statements(("name:endautoescape",), drop_needle=True)
 294        return nodes.Scope([node])
 295
 296    def parse_block(self) -> nodes.Block:
 297        node = nodes.Block(lineno=next(self.stream).lineno)
 298        node.name = self.stream.expect("name").value
 299        node.scoped = self.stream.skip_if("name:scoped")
 300        node.required = self.stream.skip_if("name:required")
 301
 302        # common problem people encounter when switching from django
 303        # to jinja.  we do not support hyphens in block names, so let's
 304        # raise a nicer error message in that case.
 305        if self.stream.current.type == "sub":
 306            self.fail(
 307                "Block names in Jinja have to be valid Python identifiers and may not"
 308                " contain hyphens, use an underscore instead."
 309            )
 310
 311        node.body = self.parse_statements(("name:endblock",), drop_needle=True)
 312
 313        # enforce that required blocks only contain whitespace or comments
 314        # by asserting that the body, if not empty, is just TemplateData nodes
 315        # with whitespace data
 316        if node.required:
 317            for body_node in node.body:
 318                if not isinstance(body_node, nodes.Output) or any(
 319                    not isinstance(output_node, nodes.TemplateData)
 320                    or not output_node.data.isspace()
 321                    for output_node in body_node.nodes
 322                ):
 323                    self.fail("Required blocks can only contain comments or whitespace")
 324
 325        self.stream.skip_if("name:" + node.name)
 326        return node
 327
 328    def parse_extends(self) -> nodes.Extends:
 329        node = nodes.Extends(lineno=next(self.stream).lineno)
 330        node.template = self.parse_expression()
 331        return node
 332
 333    def parse_import_context(
 334        self, node: _ImportInclude, default: bool
 335    ) -> _ImportInclude:
 336        if self.stream.current.test_any(
 337            "name:with", "name:without"
 338        ) and self.stream.look().test("name:context"):
 339            node.with_context = next(self.stream).value == "with"
 340            self.stream.skip()
 341        else:
 342            node.with_context = default
 343        return node
 344
 345    def parse_include(self) -> nodes.Include:
 346        node = nodes.Include(lineno=next(self.stream).lineno)
 347        node.template = self.parse_expression()
 348        if self.stream.current.test("name:ignore") and self.stream.look().test(
 349            "name:missing"
 350        ):
 351            node.ignore_missing = True
 352            self.stream.skip(2)
 353        else:
 354            node.ignore_missing = False
 355        return self.parse_import_context(node, True)
 356
 357    def parse_import(self) -> nodes.Import:
 358        node = nodes.Import(lineno=next(self.stream).lineno)
 359        node.template = self.parse_expression()
 360        self.stream.expect("name:as")
 361        node.target = self.parse_assign_target(name_only=True).name
 362        return self.parse_import_context(node, False)
 363
 364    def parse_from(self) -> nodes.FromImport:
 365        node = nodes.FromImport(lineno=next(self.stream).lineno)
 366        node.template = self.parse_expression()
 367        self.stream.expect("name:import")
 368        node.names = []
 369
 370        def parse_context() -> bool:
 371            if self.stream.current.value in {
 372                "with",
 373                "without",
 374            } and self.stream.look().test("name:context"):
 375                node.with_context = next(self.stream).value == "with"
 376                self.stream.skip()
 377                return True
 378            return False
 379
 380        while True:
 381            if node.names:
 382                self.stream.expect("comma")
 383            if self.stream.current.type == "name":
 384                if parse_context():
 385                    break
 386                target = self.parse_assign_target(name_only=True)
 387                if target.name.startswith("_"):
 388                    self.fail(
 389                        "names starting with an underline can not be imported",
 390                        target.lineno,
 391                        exc=TemplateAssertionError,
 392                    )
 393                if self.stream.skip_if("name:as"):
 394                    alias = self.parse_assign_target(name_only=True)
 395                    node.names.append((target.name, alias.name))
 396                else:
 397                    node.names.append(target.name)
 398                if parse_context() or self.stream.current.type != "comma":
 399                    break
 400            else:
 401                self.stream.expect("name")
 402        if not hasattr(node, "with_context"):
 403            node.with_context = False
 404        return node
 405
 406    def parse_signature(self, node: _MacroCall) -> None:
 407        args = node.args = []
 408        defaults = node.defaults = []
 409        self.stream.expect("lparen")
 410        while self.stream.current.type != "rparen":
 411            if args:
 412                self.stream.expect("comma")
 413            arg = self.parse_assign_target(name_only=True)
 414            arg.set_ctx("param")
 415            if self.stream.skip_if("assign"):
 416                defaults.append(self.parse_expression())
 417            elif defaults:
 418                self.fail("non-default argument follows default argument")
 419            args.append(arg)
 420        self.stream.expect("rparen")
 421
 422    def parse_call_block(self) -> nodes.CallBlock:
 423        node = nodes.CallBlock(lineno=next(self.stream).lineno)
 424        if self.stream.current.type == "lparen":
 425            self.parse_signature(node)
 426        else:
 427            node.args = []
 428            node.defaults = []
 429
 430        call_node = self.parse_expression()
 431        if not isinstance(call_node, nodes.Call):
 432            self.fail("expected call", node.lineno)
 433        node.call = call_node
 434        node.body = self.parse_statements(("name:endcall",), drop_needle=True)
 435        return node
 436
 437    def parse_filter_block(self) -> nodes.FilterBlock:
 438        node = nodes.FilterBlock(lineno=next(self.stream).lineno)
 439        node.filter = self.parse_filter(None, start_inline=True)  # type: ignore
 440        node.body = self.parse_statements(("name:endfilter",), drop_needle=True)
 441        return node
 442
 443    def parse_macro(self) -> nodes.Macro:
 444        node = nodes.Macro(lineno=next(self.stream).lineno)
 445        node.name = self.parse_assign_target(name_only=True).name
 446        self.parse_signature(node)
 447        node.body = self.parse_statements(("name:endmacro",), drop_needle=True)
 448        return node
 449
 450    def parse_print(self) -> nodes.Output:
 451        node = nodes.Output(lineno=next(self.stream).lineno)
 452        node.nodes = []
 453        while self.stream.current.type != "block_end":
 454            if node.nodes:
 455                self.stream.expect("comma")
 456            node.nodes.append(self.parse_expression())
 457        return node
 458
 459    @typing.overload
 460    def parse_assign_target(
 461        self, with_tuple: bool = ..., name_only: "te.Literal[True]" = ...
 462    ) -> nodes.Name: ...
 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    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(
 865        self,
 866    ) -> t.Tuple[
 867        t.List[nodes.Expr],
 868        t.List[nodes.Keyword],
 869        t.Optional[nodes.Expr],
 870        t.Optional[nodes.Expr],
 871    ]:
 872        token = self.stream.expect("lparen")
 873        args = []
 874        kwargs = []
 875        dyn_args = None
 876        dyn_kwargs = None
 877        require_comma = False
 878
 879        def ensure(expr: bool) -> None:
 880            if not expr:
 881                self.fail("invalid syntax for function call expression", token.lineno)
 882
 883        while self.stream.current.type != "rparen":
 884            if require_comma:
 885                self.stream.expect("comma")
 886
 887                # support for trailing comma
 888                if self.stream.current.type == "rparen":
 889                    break
 890
 891            if self.stream.current.type == "mul":
 892                ensure(dyn_args is None and dyn_kwargs is None)
 893                next(self.stream)
 894                dyn_args = self.parse_expression()
 895            elif self.stream.current.type == "pow":
 896                ensure(dyn_kwargs is None)
 897                next(self.stream)
 898                dyn_kwargs = self.parse_expression()
 899            else:
 900                if (
 901                    self.stream.current.type == "name"
 902                    and self.stream.look().type == "assign"
 903                ):
 904                    # Parsing a kwarg
 905                    ensure(dyn_kwargs is None)
 906                    key = self.stream.current.value
 907                    self.stream.skip(2)
 908                    value = self.parse_expression()
 909                    kwargs.append(nodes.Keyword(key, value, lineno=value.lineno))
 910                else:
 911                    # Parsing an arg
 912                    ensure(dyn_args is None and dyn_kwargs is None and not kwargs)
 913                    args.append(self.parse_expression())
 914
 915            require_comma = True
 916
 917        self.stream.expect("rparen")
 918        return args, kwargs, dyn_args, dyn_kwargs
 919
 920    def parse_call(self, node: nodes.Expr) -> nodes.Call:
 921        # The lparen will be expected in parse_call_args, but the lineno
 922        # needs to be recorded before the stream is advanced.
 923        token = self.stream.current
 924        args, kwargs, dyn_args, dyn_kwargs = self.parse_call_args()
 925        return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno)
 926
 927    def parse_filter(
 928        self, node: t.Optional[nodes.Expr], start_inline: bool = False
 929    ) -> t.Optional[nodes.Expr]:
 930        while self.stream.current.type == "pipe" or start_inline:
 931            if not start_inline:
 932                next(self.stream)
 933            token = self.stream.expect("name")
 934            name = token.value
 935            while self.stream.current.type == "dot":
 936                next(self.stream)
 937                name += "." + self.stream.expect("name").value
 938            if self.stream.current.type == "lparen":
 939                args, kwargs, dyn_args, dyn_kwargs = self.parse_call_args()
 940            else:
 941                args = []
 942                kwargs = []
 943                dyn_args = dyn_kwargs = None
 944            node = nodes.Filter(
 945                node, name, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno
 946            )
 947            start_inline = False
 948        return node
 949
 950    def parse_test(self, node: nodes.Expr) -> nodes.Expr:
 951        token = next(self.stream)
 952        if self.stream.current.test("name:not"):
 953            next(self.stream)
 954            negated = True
 955        else:
 956            negated = False
 957        name = self.stream.expect("name").value
 958        while self.stream.current.type == "dot":
 959            next(self.stream)
 960            name += "." + self.stream.expect("name").value
 961        dyn_args = dyn_kwargs = None
 962        kwargs: t.List[nodes.Keyword] = []
 963        if self.stream.current.type == "lparen":
 964            args, kwargs, dyn_args, dyn_kwargs = self.parse_call_args()
 965        elif self.stream.current.type in {
 966            "name",
 967            "string",
 968            "integer",
 969            "float",
 970            "lparen",
 971            "lbracket",
 972            "lbrace",
 973        } and not self.stream.current.test_any("name:else", "name:or", "name:and"):
 974            if self.stream.current.test("name:is"):
 975                self.fail("You cannot chain multiple tests with is")
 976            arg_node = self.parse_primary()
 977            arg_node = self.parse_postfix(arg_node)
 978            args = [arg_node]
 979        else:
 980            args = []
 981        node = nodes.Test(
 982            node, name, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno
 983        )
 984        if negated:
 985            node = nodes.Not(node, lineno=token.lineno)
 986        return node
 987
 988    def subparse(
 989        self, end_tokens: t.Optional[t.Tuple[str, ...]] = None
 990    ) -> t.List[nodes.Node]:
 991        body: t.List[nodes.Node] = []
 992        data_buffer: t.List[nodes.Node] = []
 993        add_data = data_buffer.append
 994
 995        if end_tokens is not None:
 996            self._end_token_stack.append(end_tokens)
 997
 998        def flush_data() -> None:
 999            if data_buffer:
1000                lineno = data_buffer[0].lineno
1001                body.append(nodes.Output(data_buffer[:], lineno=lineno))
1002                del data_buffer[:]
1003
1004        try:
1005            while self.stream:
1006                token = self.stream.current
1007                if token.type == "data":
1008                    if token.value:
1009                        add_data(nodes.TemplateData(token.value, lineno=token.lineno))
1010                    next(self.stream)
1011                elif token.type == "variable_begin":
1012                    next(self.stream)
1013                    add_data(self.parse_tuple(with_condexpr=True))
1014                    self.stream.expect("variable_end")
1015                elif token.type == "block_begin":
1016                    flush_data()
1017                    next(self.stream)
1018                    if end_tokens is not None and self.stream.current.test_any(
1019                        *end_tokens
1020                    ):
1021                        return body
1022                    rv = self.parse_statement()
1023                    if isinstance(rv, list):
1024                        body.extend(rv)
1025                    else:
1026                        body.append(rv)
1027                    self.stream.expect("block_end")
1028                else:
1029                    raise AssertionError("internal parsing error")
1030
1031            flush_data()
1032        finally:
1033            if end_tokens is not None:
1034                self._end_token_stack.pop()
1035        return body
1036
1037    def parse(self) -> nodes.Template:
1038        """Parse the whole template into a `Template` node."""
1039        result = nodes.Template(self.subparse(), lineno=1)
1040        result.set_environment(self.environment)
1041        return result
class Parser:
  49class Parser:
  50    """This is the central parsing class Jinja uses.  It's passed to
  51    extensions and can be used to parse expressions or statements.
  52    """
  53
  54    def __init__(
  55        self,
  56        environment: "Environment",
  57        source: str,
  58        name: t.Optional[str] = None,
  59        filename: t.Optional[str] = None,
  60        state: t.Optional[str] = None,
  61    ) -> None:
  62        self.environment = environment
  63        self.stream = environment._tokenize(source, name, filename, state)
  64        self.name = name
  65        self.filename = filename
  66        self.closed = False
  67        self.extensions: t.Dict[
  68            str, t.Callable[["Parser"], t.Union[nodes.Node, t.List[nodes.Node]]]
  69        ] = {}
  70        for extension in environment.iter_extensions():
  71            for tag in extension.tags:
  72                self.extensions[tag] = extension.parse
  73        self._last_identifier = 0
  74        self._tag_stack: t.List[str] = []
  75        self._end_token_stack: t.List[t.Tuple[str, ...]] = []
  76
  77    def fail(
  78        self,
  79        msg: str,
  80        lineno: t.Optional[int] = None,
  81        exc: t.Type[TemplateSyntaxError] = TemplateSyntaxError,
  82    ) -> "te.NoReturn":
  83        """Convenience method that raises `exc` with the message, passed
  84        line number or last line number as well as the current name and
  85        filename.
  86        """
  87        if lineno is None:
  88            lineno = self.stream.current.lineno
  89        raise exc(msg, lineno, self.name, self.filename)
  90
  91    def _fail_ut_eof(
  92        self,
  93        name: t.Optional[str],
  94        end_token_stack: t.List[t.Tuple[str, ...]],
  95        lineno: t.Optional[int],
  96    ) -> "te.NoReturn":
  97        expected: t.Set[str] = set()
  98        for exprs in end_token_stack:
  99            expected.update(map(describe_token_expr, exprs))
 100        if end_token_stack:
 101            currently_looking: t.Optional[str] = " or ".join(
 102                map(repr, map(describe_token_expr, end_token_stack[-1]))
 103            )
 104        else:
 105            currently_looking = None
 106
 107        if name is None:
 108            message = ["Unexpected end of template."]
 109        else:
 110            message = [f"Encountered unknown tag {name!r}."]
 111
 112        if currently_looking:
 113            if name is not None and name in expected:
 114                message.append(
 115                    "You probably made a nesting mistake. Jinja is expecting this tag,"
 116                    f" but currently looking for {currently_looking}."
 117                )
 118            else:
 119                message.append(
 120                    f"Jinja was looking for the following tags: {currently_looking}."
 121                )
 122
 123        if self._tag_stack:
 124            message.append(
 125                "The innermost block that needs to be closed is"
 126                f" {self._tag_stack[-1]!r}."
 127            )
 128
 129        self.fail(" ".join(message), lineno)
 130
 131    def fail_unknown_tag(
 132        self, name: str, lineno: t.Optional[int] = None
 133    ) -> "te.NoReturn":
 134        """Called if the parser encounters an unknown tag.  Tries to fail
 135        with a human readable error message that could help to identify
 136        the problem.
 137        """
 138        self._fail_ut_eof(name, self._end_token_stack, lineno)
 139
 140    def fail_eof(
 141        self,
 142        end_tokens: t.Optional[t.Tuple[str, ...]] = None,
 143        lineno: t.Optional[int] = None,
 144    ) -> "te.NoReturn":
 145        """Like fail_unknown_tag but for end of template situations."""
 146        stack = list(self._end_token_stack)
 147        if end_tokens is not None:
 148            stack.append(end_tokens)
 149        self._fail_ut_eof(None, stack, lineno)
 150
 151    def is_tuple_end(
 152        self, extra_end_rules: t.Optional[t.Tuple[str, ...]] = None
 153    ) -> bool:
 154        """Are we at the end of a tuple?"""
 155        if self.stream.current.type in ("variable_end", "block_end", "rparen"):
 156            return True
 157        elif extra_end_rules is not None:
 158            return self.stream.current.test_any(extra_end_rules)  # type: ignore
 159        return False
 160
 161    def free_identifier(self, lineno: t.Optional[int] = None) -> nodes.InternalName:
 162        """Return a new free identifier as :class:`~jinja2.nodes.InternalName`."""
 163        self._last_identifier += 1
 164        rv = object.__new__(nodes.InternalName)
 165        nodes.Node.__init__(rv, f"fi{self._last_identifier}", lineno=lineno)
 166        return rv
 167
 168    def parse_statement(self) -> t.Union[nodes.Node, t.List[nodes.Node]]:
 169        """Parse a single statement."""
 170        token = self.stream.current
 171        if token.type != "name":
 172            self.fail("tag name expected", token.lineno)
 173        self._tag_stack.append(token.value)
 174        pop_tag = True
 175        try:
 176            if token.value in _statement_keywords:
 177                f = getattr(self, f"parse_{self.stream.current.value}")
 178                return f()  # type: ignore
 179            if token.value == "call":
 180                return self.parse_call_block()
 181            if token.value == "filter":
 182                return self.parse_filter_block()
 183            ext = self.extensions.get(token.value)
 184            if ext is not None:
 185                return ext(self)
 186
 187            # did not work out, remove the token we pushed by accident
 188            # from the stack so that the unknown tag fail function can
 189            # produce a proper error message.
 190            self._tag_stack.pop()
 191            pop_tag = False
 192            self.fail_unknown_tag(token.value, token.lineno)
 193        finally:
 194            if pop_tag:
 195                self._tag_stack.pop()
 196
 197    def parse_statements(
 198        self, end_tokens: t.Tuple[str, ...], drop_needle: bool = False
 199    ) -> t.List[nodes.Node]:
 200        """Parse multiple statements into a list until one of the end tokens
 201        is reached.  This is used to parse the body of statements as it also
 202        parses template data if appropriate.  The parser checks first if the
 203        current token is a colon and skips it if there is one.  Then it checks
 204        for the block end and parses until if one of the `end_tokens` is
 205        reached.  Per default the active token in the stream at the end of
 206        the call is the matched end token.  If this is not wanted `drop_needle`
 207        can be set to `True` and the end token is removed.
 208        """
 209        # the first token may be a colon for python compatibility
 210        self.stream.skip_if("colon")
 211
 212        # in the future it would be possible to add whole code sections
 213        # by adding some sort of end of statement token and parsing those here.
 214        self.stream.expect("block_end")
 215        result = self.subparse(end_tokens)
 216
 217        # we reached the end of the template too early, the subparser
 218        # does not check for this, so we do that now
 219        if self.stream.current.type == "eof":
 220            self.fail_eof(end_tokens)
 221
 222        if drop_needle:
 223            next(self.stream)
 224        return result
 225
 226    def parse_set(self) -> t.Union[nodes.Assign, nodes.AssignBlock]:
 227        """Parse an assign statement."""
 228        lineno = next(self.stream).lineno
 229        target = self.parse_assign_target(with_namespace=True)
 230        if self.stream.skip_if("assign"):
 231            expr = self.parse_tuple()
 232            return nodes.Assign(target, expr, lineno=lineno)
 233        filter_node = self.parse_filter(None)
 234        body = self.parse_statements(("name:endset",), drop_needle=True)
 235        return nodes.AssignBlock(target, filter_node, body, lineno=lineno)
 236
 237    def parse_for(self) -> nodes.For:
 238        """Parse a for loop."""
 239        lineno = self.stream.expect("name:for").lineno
 240        target = self.parse_assign_target(extra_end_rules=("name:in",))
 241        self.stream.expect("name:in")
 242        iter = self.parse_tuple(
 243            with_condexpr=False, extra_end_rules=("name:recursive",)
 244        )
 245        test = None
 246        if self.stream.skip_if("name:if"):
 247            test = self.parse_expression()
 248        recursive = self.stream.skip_if("name:recursive")
 249        body = self.parse_statements(("name:endfor", "name:else"))
 250        if next(self.stream).value == "endfor":
 251            else_ = []
 252        else:
 253            else_ = self.parse_statements(("name:endfor",), drop_needle=True)
 254        return nodes.For(target, iter, body, else_, test, recursive, lineno=lineno)
 255
 256    def parse_if(self) -> nodes.If:
 257        """Parse an if construct."""
 258        node = result = nodes.If(lineno=self.stream.expect("name:if").lineno)
 259        while True:
 260            node.test = self.parse_tuple(with_condexpr=False)
 261            node.body = self.parse_statements(("name:elif", "name:else", "name:endif"))
 262            node.elif_ = []
 263            node.else_ = []
 264            token = next(self.stream)
 265            if token.test("name:elif"):
 266                node = nodes.If(lineno=self.stream.current.lineno)
 267                result.elif_.append(node)
 268                continue
 269            elif token.test("name:else"):
 270                result.else_ = self.parse_statements(("name:endif",), drop_needle=True)
 271            break
 272        return result
 273
 274    def parse_with(self) -> nodes.With:
 275        node = nodes.With(lineno=next(self.stream).lineno)
 276        targets: t.List[nodes.Expr] = []
 277        values: t.List[nodes.Expr] = []
 278        while self.stream.current.type != "block_end":
 279            if targets:
 280                self.stream.expect("comma")
 281            target = self.parse_assign_target()
 282            target.set_ctx("param")
 283            targets.append(target)
 284            self.stream.expect("assign")
 285            values.append(self.parse_expression())
 286        node.targets = targets
 287        node.values = values
 288        node.body = self.parse_statements(("name:endwith",), drop_needle=True)
 289        return node
 290
 291    def parse_autoescape(self) -> nodes.Scope:
 292        node = nodes.ScopedEvalContextModifier(lineno=next(self.stream).lineno)
 293        node.options = [nodes.Keyword("autoescape", self.parse_expression())]
 294        node.body = self.parse_statements(("name:endautoescape",), drop_needle=True)
 295        return nodes.Scope([node])
 296
 297    def parse_block(self) -> nodes.Block:
 298        node = nodes.Block(lineno=next(self.stream).lineno)
 299        node.name = self.stream.expect("name").value
 300        node.scoped = self.stream.skip_if("name:scoped")
 301        node.required = self.stream.skip_if("name:required")
 302
 303        # common problem people encounter when switching from django
 304        # to jinja.  we do not support hyphens in block names, so let's
 305        # raise a nicer error message in that case.
 306        if self.stream.current.type == "sub":
 307            self.fail(
 308                "Block names in Jinja have to be valid Python identifiers and may not"
 309                " contain hyphens, use an underscore instead."
 310            )
 311
 312        node.body = self.parse_statements(("name:endblock",), drop_needle=True)
 313
 314        # enforce that required blocks only contain whitespace or comments
 315        # by asserting that the body, if not empty, is just TemplateData nodes
 316        # with whitespace data
 317        if node.required:
 318            for body_node in node.body:
 319                if not isinstance(body_node, nodes.Output) or any(
 320                    not isinstance(output_node, nodes.TemplateData)
 321                    or not output_node.data.isspace()
 322                    for output_node in body_node.nodes
 323                ):
 324                    self.fail("Required blocks can only contain comments or whitespace")
 325
 326        self.stream.skip_if("name:" + node.name)
 327        return node
 328
 329    def parse_extends(self) -> nodes.Extends:
 330        node = nodes.Extends(lineno=next(self.stream).lineno)
 331        node.template = self.parse_expression()
 332        return node
 333
 334    def parse_import_context(
 335        self, node: _ImportInclude, default: bool
 336    ) -> _ImportInclude:
 337        if self.stream.current.test_any(
 338            "name:with", "name:without"
 339        ) and self.stream.look().test("name:context"):
 340            node.with_context = next(self.stream).value == "with"
 341            self.stream.skip()
 342        else:
 343            node.with_context = default
 344        return node
 345
 346    def parse_include(self) -> nodes.Include:
 347        node = nodes.Include(lineno=next(self.stream).lineno)
 348        node.template = self.parse_expression()
 349        if self.stream.current.test("name:ignore") and self.stream.look().test(
 350            "name:missing"
 351        ):
 352            node.ignore_missing = True
 353            self.stream.skip(2)
 354        else:
 355            node.ignore_missing = False
 356        return self.parse_import_context(node, True)
 357
 358    def parse_import(self) -> nodes.Import:
 359        node = nodes.Import(lineno=next(self.stream).lineno)
 360        node.template = self.parse_expression()
 361        self.stream.expect("name:as")
 362        node.target = self.parse_assign_target(name_only=True).name
 363        return self.parse_import_context(node, False)
 364
 365    def parse_from(self) -> nodes.FromImport:
 366        node = nodes.FromImport(lineno=next(self.stream).lineno)
 367        node.template = self.parse_expression()
 368        self.stream.expect("name:import")
 369        node.names = []
 370
 371        def parse_context() -> bool:
 372            if self.stream.current.value in {
 373                "with",
 374                "without",
 375            } and self.stream.look().test("name:context"):
 376                node.with_context = next(self.stream).value == "with"
 377                self.stream.skip()
 378                return True
 379            return False
 380
 381        while True:
 382            if node.names:
 383                self.stream.expect("comma")
 384            if self.stream.current.type == "name":
 385                if parse_context():
 386                    break
 387                target = self.parse_assign_target(name_only=True)
 388                if target.name.startswith("_"):
 389                    self.fail(
 390                        "names starting with an underline can not be imported",
 391                        target.lineno,
 392                        exc=TemplateAssertionError,
 393                    )
 394                if self.stream.skip_if("name:as"):
 395                    alias = self.parse_assign_target(name_only=True)
 396                    node.names.append((target.name, alias.name))
 397                else:
 398                    node.names.append(target.name)
 399                if parse_context() or self.stream.current.type != "comma":
 400                    break
 401            else:
 402                self.stream.expect("name")
 403        if not hasattr(node, "with_context"):
 404            node.with_context = False
 405        return node
 406
 407    def parse_signature(self, node: _MacroCall) -> None:
 408        args = node.args = []
 409        defaults = node.defaults = []
 410        self.stream.expect("lparen")
 411        while self.stream.current.type != "rparen":
 412            if args:
 413                self.stream.expect("comma")
 414            arg = self.parse_assign_target(name_only=True)
 415            arg.set_ctx("param")
 416            if self.stream.skip_if("assign"):
 417                defaults.append(self.parse_expression())
 418            elif defaults:
 419                self.fail("non-default argument follows default argument")
 420            args.append(arg)
 421        self.stream.expect("rparen")
 422
 423    def parse_call_block(self) -> nodes.CallBlock:
 424        node = nodes.CallBlock(lineno=next(self.stream).lineno)
 425        if self.stream.current.type == "lparen":
 426            self.parse_signature(node)
 427        else:
 428            node.args = []
 429            node.defaults = []
 430
 431        call_node = self.parse_expression()
 432        if not isinstance(call_node, nodes.Call):
 433            self.fail("expected call", node.lineno)
 434        node.call = call_node
 435        node.body = self.parse_statements(("name:endcall",), drop_needle=True)
 436        return node
 437
 438    def parse_filter_block(self) -> nodes.FilterBlock:
 439        node = nodes.FilterBlock(lineno=next(self.stream).lineno)
 440        node.filter = self.parse_filter(None, start_inline=True)  # type: ignore
 441        node.body = self.parse_statements(("name:endfilter",), drop_needle=True)
 442        return node
 443
 444    def parse_macro(self) -> nodes.Macro:
 445        node = nodes.Macro(lineno=next(self.stream).lineno)
 446        node.name = self.parse_assign_target(name_only=True).name
 447        self.parse_signature(node)
 448        node.body = self.parse_statements(("name:endmacro",), drop_needle=True)
 449        return node
 450
 451    def parse_print(self) -> nodes.Output:
 452        node = nodes.Output(lineno=next(self.stream).lineno)
 453        node.nodes = []
 454        while self.stream.current.type != "block_end":
 455            if node.nodes:
 456                self.stream.expect("comma")
 457            node.nodes.append(self.parse_expression())
 458        return node
 459
 460    @typing.overload
 461    def parse_assign_target(
 462        self, with_tuple: bool = ..., name_only: "te.Literal[True]" = ...
 463    ) -> nodes.Name: ...
 464
 465    @typing.overload
 466    def parse_assign_target(
 467        self,
 468        with_tuple: bool = True,
 469        name_only: bool = False,
 470        extra_end_rules: t.Optional[t.Tuple[str, ...]] = None,
 471        with_namespace: bool = False,
 472    ) -> t.Union[nodes.NSRef, nodes.Name, nodes.Tuple]: ...
 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(
 866        self,
 867    ) -> t.Tuple[
 868        t.List[nodes.Expr],
 869        t.List[nodes.Keyword],
 870        t.Optional[nodes.Expr],
 871        t.Optional[nodes.Expr],
 872    ]:
 873        token = self.stream.expect("lparen")
 874        args = []
 875        kwargs = []
 876        dyn_args = None
 877        dyn_kwargs = None
 878        require_comma = False
 879
 880        def ensure(expr: bool) -> None:
 881            if not expr:
 882                self.fail("invalid syntax for function call expression", token.lineno)
 883
 884        while self.stream.current.type != "rparen":
 885            if require_comma:
 886                self.stream.expect("comma")
 887
 888                # support for trailing comma
 889                if self.stream.current.type == "rparen":
 890                    break
 891
 892            if self.stream.current.type == "mul":
 893                ensure(dyn_args is None and dyn_kwargs is None)
 894                next(self.stream)
 895                dyn_args = self.parse_expression()
 896            elif self.stream.current.type == "pow":
 897                ensure(dyn_kwargs is None)
 898                next(self.stream)
 899                dyn_kwargs = self.parse_expression()
 900            else:
 901                if (
 902                    self.stream.current.type == "name"
 903                    and self.stream.look().type == "assign"
 904                ):
 905                    # Parsing a kwarg
 906                    ensure(dyn_kwargs is None)
 907                    key = self.stream.current.value
 908                    self.stream.skip(2)
 909                    value = self.parse_expression()
 910                    kwargs.append(nodes.Keyword(key, value, lineno=value.lineno))
 911                else:
 912                    # Parsing an arg
 913                    ensure(dyn_args is None and dyn_kwargs is None and not kwargs)
 914                    args.append(self.parse_expression())
 915
 916            require_comma = True
 917
 918        self.stream.expect("rparen")
 919        return args, kwargs, dyn_args, dyn_kwargs
 920
 921    def parse_call(self, node: nodes.Expr) -> nodes.Call:
 922        # The lparen will be expected in parse_call_args, but the lineno
 923        # needs to be recorded before the stream is advanced.
 924        token = self.stream.current
 925        args, kwargs, dyn_args, dyn_kwargs = self.parse_call_args()
 926        return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno)
 927
 928    def parse_filter(
 929        self, node: t.Optional[nodes.Expr], start_inline: bool = False
 930    ) -> t.Optional[nodes.Expr]:
 931        while self.stream.current.type == "pipe" or start_inline:
 932            if not start_inline:
 933                next(self.stream)
 934            token = self.stream.expect("name")
 935            name = token.value
 936            while self.stream.current.type == "dot":
 937                next(self.stream)
 938                name += "." + self.stream.expect("name").value
 939            if self.stream.current.type == "lparen":
 940                args, kwargs, dyn_args, dyn_kwargs = self.parse_call_args()
 941            else:
 942                args = []
 943                kwargs = []
 944                dyn_args = dyn_kwargs = None
 945            node = nodes.Filter(
 946                node, name, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno
 947            )
 948            start_inline = False
 949        return node
 950
 951    def parse_test(self, node: nodes.Expr) -> nodes.Expr:
 952        token = next(self.stream)
 953        if self.stream.current.test("name:not"):
 954            next(self.stream)
 955            negated = True
 956        else:
 957            negated = False
 958        name = self.stream.expect("name").value
 959        while self.stream.current.type == "dot":
 960            next(self.stream)
 961            name += "." + self.stream.expect("name").value
 962        dyn_args = dyn_kwargs = None
 963        kwargs: t.List[nodes.Keyword] = []
 964        if self.stream.current.type == "lparen":
 965            args, kwargs, dyn_args, dyn_kwargs = self.parse_call_args()
 966        elif self.stream.current.type in {
 967            "name",
 968            "string",
 969            "integer",
 970            "float",
 971            "lparen",
 972            "lbracket",
 973            "lbrace",
 974        } and not self.stream.current.test_any("name:else", "name:or", "name:and"):
 975            if self.stream.current.test("name:is"):
 976                self.fail("You cannot chain multiple tests with is")
 977            arg_node = self.parse_primary()
 978            arg_node = self.parse_postfix(arg_node)
 979            args = [arg_node]
 980        else:
 981            args = []
 982        node = nodes.Test(
 983            node, name, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno
 984        )
 985        if negated:
 986            node = nodes.Not(node, lineno=token.lineno)
 987        return node
 988
 989    def subparse(
 990        self, end_tokens: t.Optional[t.Tuple[str, ...]] = None
 991    ) -> t.List[nodes.Node]:
 992        body: t.List[nodes.Node] = []
 993        data_buffer: t.List[nodes.Node] = []
 994        add_data = data_buffer.append
 995
 996        if end_tokens is not None:
 997            self._end_token_stack.append(end_tokens)
 998
 999        def flush_data() -> None:
1000            if data_buffer:
1001                lineno = data_buffer[0].lineno
1002                body.append(nodes.Output(data_buffer[:], lineno=lineno))
1003                del data_buffer[:]
1004
1005        try:
1006            while self.stream:
1007                token = self.stream.current
1008                if token.type == "data":
1009                    if token.value:
1010                        add_data(nodes.TemplateData(token.value, lineno=token.lineno))
1011                    next(self.stream)
1012                elif token.type == "variable_begin":
1013                    next(self.stream)
1014                    add_data(self.parse_tuple(with_condexpr=True))
1015                    self.stream.expect("variable_end")
1016                elif token.type == "block_begin":
1017                    flush_data()
1018                    next(self.stream)
1019                    if end_tokens is not None and self.stream.current.test_any(
1020                        *end_tokens
1021                    ):
1022                        return body
1023                    rv = self.parse_statement()
1024                    if isinstance(rv, list):
1025                        body.extend(rv)
1026                    else:
1027                        body.append(rv)
1028                    self.stream.expect("block_end")
1029                else:
1030                    raise AssertionError("internal parsing error")
1031
1032            flush_data()
1033        finally:
1034            if end_tokens is not None:
1035                self._end_token_stack.pop()
1036        return body
1037
1038    def parse(self) -> nodes.Template:
1039        """Parse the whole template into a `Template` node."""
1040        result = nodes.Template(self.subparse(), lineno=1)
1041        result.set_environment(self.environment)
1042        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)
54    def __init__(
55        self,
56        environment: "Environment",
57        source: str,
58        name: t.Optional[str] = None,
59        filename: t.Optional[str] = None,
60        state: t.Optional[str] = None,
61    ) -> None:
62        self.environment = environment
63        self.stream = environment._tokenize(source, name, filename, state)
64        self.name = name
65        self.filename = filename
66        self.closed = False
67        self.extensions: t.Dict[
68            str, t.Callable[["Parser"], t.Union[nodes.Node, t.List[nodes.Node]]]
69        ] = {}
70        for extension in environment.iter_extensions():
71            for tag in extension.tags:
72                self.extensions[tag] = extension.parse
73        self._last_identifier = 0
74        self._tag_stack: t.List[str] = []
75        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:
77    def fail(
78        self,
79        msg: str,
80        lineno: t.Optional[int] = None,
81        exc: t.Type[TemplateSyntaxError] = TemplateSyntaxError,
82    ) -> "te.NoReturn":
83        """Convenience method that raises `exc` with the message, passed
84        line number or last line number as well as the current name and
85        filename.
86        """
87        if lineno is None:
88            lineno = self.stream.current.lineno
89        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:
131    def fail_unknown_tag(
132        self, name: str, lineno: t.Optional[int] = None
133    ) -> "te.NoReturn":
134        """Called if the parser encounters an unknown tag.  Tries to fail
135        with a human readable error message that could help to identify
136        the problem.
137        """
138        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:
140    def fail_eof(
141        self,
142        end_tokens: t.Optional[t.Tuple[str, ...]] = None,
143        lineno: t.Optional[int] = None,
144    ) -> "te.NoReturn":
145        """Like fail_unknown_tag but for end of template situations."""
146        stack = list(self._end_token_stack)
147        if end_tokens is not None:
148            stack.append(end_tokens)
149        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:
151    def is_tuple_end(
152        self, extra_end_rules: t.Optional[t.Tuple[str, ...]] = None
153    ) -> bool:
154        """Are we at the end of a tuple?"""
155        if self.stream.current.type in ("variable_end", "block_end", "rparen"):
156            return True
157        elif extra_end_rules is not None:
158            return self.stream.current.test_any(extra_end_rules)  # type: ignore
159        return False

Are we at the end of a tuple?

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

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

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

Parse a single statement.

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

Parse an assign statement.

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

Parse a for loop.

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

Parse an if construct.

def parse_with(self) -> jinja2.nodes.With:
274    def parse_with(self) -> nodes.With:
275        node = nodes.With(lineno=next(self.stream).lineno)
276        targets: t.List[nodes.Expr] = []
277        values: t.List[nodes.Expr] = []
278        while self.stream.current.type != "block_end":
279            if targets:
280                self.stream.expect("comma")
281            target = self.parse_assign_target()
282            target.set_ctx("param")
283            targets.append(target)
284            self.stream.expect("assign")
285            values.append(self.parse_expression())
286        node.targets = targets
287        node.values = values
288        node.body = self.parse_statements(("name:endwith",), drop_needle=True)
289        return node
def parse_autoescape(self) -> jinja2.nodes.Scope:
291    def parse_autoescape(self) -> nodes.Scope:
292        node = nodes.ScopedEvalContextModifier(lineno=next(self.stream).lineno)
293        node.options = [nodes.Keyword("autoescape", self.parse_expression())]
294        node.body = self.parse_statements(("name:endautoescape",), drop_needle=True)
295        return nodes.Scope([node])
def parse_block(self) -> jinja2.nodes.Block:
297    def parse_block(self) -> nodes.Block:
298        node = nodes.Block(lineno=next(self.stream).lineno)
299        node.name = self.stream.expect("name").value
300        node.scoped = self.stream.skip_if("name:scoped")
301        node.required = self.stream.skip_if("name:required")
302
303        # common problem people encounter when switching from django
304        # to jinja.  we do not support hyphens in block names, so let's
305        # raise a nicer error message in that case.
306        if self.stream.current.type == "sub":
307            self.fail(
308                "Block names in Jinja have to be valid Python identifiers and may not"
309                " contain hyphens, use an underscore instead."
310            )
311
312        node.body = self.parse_statements(("name:endblock",), drop_needle=True)
313
314        # enforce that required blocks only contain whitespace or comments
315        # by asserting that the body, if not empty, is just TemplateData nodes
316        # with whitespace data
317        if node.required:
318            for body_node in node.body:
319                if not isinstance(body_node, nodes.Output) or any(
320                    not isinstance(output_node, nodes.TemplateData)
321                    or not output_node.data.isspace()
322                    for output_node in body_node.nodes
323                ):
324                    self.fail("Required blocks can only contain comments or whitespace")
325
326        self.stream.skip_if("name:" + node.name)
327        return node
def parse_extends(self) -> jinja2.nodes.Extends:
329    def parse_extends(self) -> nodes.Extends:
330        node = nodes.Extends(lineno=next(self.stream).lineno)
331        node.template = self.parse_expression()
332        return node
def parse_import_context(self, node: ~_ImportInclude, default: bool) -> ~_ImportInclude:
334    def parse_import_context(
335        self, node: _ImportInclude, default: bool
336    ) -> _ImportInclude:
337        if self.stream.current.test_any(
338            "name:with", "name:without"
339        ) and self.stream.look().test("name:context"):
340            node.with_context = next(self.stream).value == "with"
341            self.stream.skip()
342        else:
343            node.with_context = default
344        return node
def parse_include(self) -> jinja2.nodes.Include:
346    def parse_include(self) -> nodes.Include:
347        node = nodes.Include(lineno=next(self.stream).lineno)
348        node.template = self.parse_expression()
349        if self.stream.current.test("name:ignore") and self.stream.look().test(
350            "name:missing"
351        ):
352            node.ignore_missing = True
353            self.stream.skip(2)
354        else:
355            node.ignore_missing = False
356        return self.parse_import_context(node, True)
def parse_import(self) -> jinja2.nodes.Import:
358    def parse_import(self) -> nodes.Import:
359        node = nodes.Import(lineno=next(self.stream).lineno)
360        node.template = self.parse_expression()
361        self.stream.expect("name:as")
362        node.target = self.parse_assign_target(name_only=True).name
363        return self.parse_import_context(node, False)
def parse_from(self) -> jinja2.nodes.FromImport:
365    def parse_from(self) -> nodes.FromImport:
366        node = nodes.FromImport(lineno=next(self.stream).lineno)
367        node.template = self.parse_expression()
368        self.stream.expect("name:import")
369        node.names = []
370
371        def parse_context() -> bool:
372            if self.stream.current.value in {
373                "with",
374                "without",
375            } and self.stream.look().test("name:context"):
376                node.with_context = next(self.stream).value == "with"
377                self.stream.skip()
378                return True
379            return False
380
381        while True:
382            if node.names:
383                self.stream.expect("comma")
384            if self.stream.current.type == "name":
385                if parse_context():
386                    break
387                target = self.parse_assign_target(name_only=True)
388                if target.name.startswith("_"):
389                    self.fail(
390                        "names starting with an underline can not be imported",
391                        target.lineno,
392                        exc=TemplateAssertionError,
393                    )
394                if self.stream.skip_if("name:as"):
395                    alias = self.parse_assign_target(name_only=True)
396                    node.names.append((target.name, alias.name))
397                else:
398                    node.names.append(target.name)
399                if parse_context() or self.stream.current.type != "comma":
400                    break
401            else:
402                self.stream.expect("name")
403        if not hasattr(node, "with_context"):
404            node.with_context = False
405        return node
def parse_signature(self, node: ~_MacroCall) -> None:
407    def parse_signature(self, node: _MacroCall) -> None:
408        args = node.args = []
409        defaults = node.defaults = []
410        self.stream.expect("lparen")
411        while self.stream.current.type != "rparen":
412            if args:
413                self.stream.expect("comma")
414            arg = self.parse_assign_target(name_only=True)
415            arg.set_ctx("param")
416            if self.stream.skip_if("assign"):
417                defaults.append(self.parse_expression())
418            elif defaults:
419                self.fail("non-default argument follows default argument")
420            args.append(arg)
421        self.stream.expect("rparen")
def parse_call_block(self) -> jinja2.nodes.CallBlock:
423    def parse_call_block(self) -> nodes.CallBlock:
424        node = nodes.CallBlock(lineno=next(self.stream).lineno)
425        if self.stream.current.type == "lparen":
426            self.parse_signature(node)
427        else:
428            node.args = []
429            node.defaults = []
430
431        call_node = self.parse_expression()
432        if not isinstance(call_node, nodes.Call):
433            self.fail("expected call", node.lineno)
434        node.call = call_node
435        node.body = self.parse_statements(("name:endcall",), drop_needle=True)
436        return node
def parse_filter_block(self) -> jinja2.nodes.FilterBlock:
438    def parse_filter_block(self) -> nodes.FilterBlock:
439        node = nodes.FilterBlock(lineno=next(self.stream).lineno)
440        node.filter = self.parse_filter(None, start_inline=True)  # type: ignore
441        node.body = self.parse_statements(("name:endfilter",), drop_needle=True)
442        return node
def parse_macro(self) -> jinja2.nodes.Macro:
444    def parse_macro(self) -> nodes.Macro:
445        node = nodes.Macro(lineno=next(self.stream).lineno)
446        node.name = self.parse_assign_target(name_only=True).name
447        self.parse_signature(node)
448        node.body = self.parse_statements(("name:endmacro",), drop_needle=True)
449        return node
def parse_print(self) -> jinja2.nodes.Output:
451    def parse_print(self) -> nodes.Output:
452        node = nodes.Output(lineno=next(self.stream).lineno)
453        node.nodes = []
454        while self.stream.current.type != "block_end":
455            if node.nodes:
456                self.stream.expect("comma")
457            node.nodes.append(self.parse_expression())
458        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[List[jinja2.nodes.Expr], List[jinja2.nodes.Keyword], Optional[jinja2.nodes.Expr], Optional[jinja2.nodes.Expr]]:
865    def parse_call_args(
866        self,
867    ) -> t.Tuple[
868        t.List[nodes.Expr],
869        t.List[nodes.Keyword],
870        t.Optional[nodes.Expr],
871        t.Optional[nodes.Expr],
872    ]:
873        token = self.stream.expect("lparen")
874        args = []
875        kwargs = []
876        dyn_args = None
877        dyn_kwargs = None
878        require_comma = False
879
880        def ensure(expr: bool) -> None:
881            if not expr:
882                self.fail("invalid syntax for function call expression", token.lineno)
883
884        while self.stream.current.type != "rparen":
885            if require_comma:
886                self.stream.expect("comma")
887
888                # support for trailing comma
889                if self.stream.current.type == "rparen":
890                    break
891
892            if self.stream.current.type == "mul":
893                ensure(dyn_args is None and dyn_kwargs is None)
894                next(self.stream)
895                dyn_args = self.parse_expression()
896            elif self.stream.current.type == "pow":
897                ensure(dyn_kwargs is None)
898                next(self.stream)
899                dyn_kwargs = self.parse_expression()
900            else:
901                if (
902                    self.stream.current.type == "name"
903                    and self.stream.look().type == "assign"
904                ):
905                    # Parsing a kwarg
906                    ensure(dyn_kwargs is None)
907                    key = self.stream.current.value
908                    self.stream.skip(2)
909                    value = self.parse_expression()
910                    kwargs.append(nodes.Keyword(key, value, lineno=value.lineno))
911                else:
912                    # Parsing an arg
913                    ensure(dyn_args is None and dyn_kwargs is None and not kwargs)
914                    args.append(self.parse_expression())
915
916            require_comma = True
917
918        self.stream.expect("rparen")
919        return args, kwargs, dyn_args, dyn_kwargs
def parse_call(self, node: jinja2.nodes.Expr) -> jinja2.nodes.Call:
921    def parse_call(self, node: nodes.Expr) -> nodes.Call:
922        # The lparen will be expected in parse_call_args, but the lineno
923        # needs to be recorded before the stream is advanced.
924        token = self.stream.current
925        args, kwargs, dyn_args, dyn_kwargs = self.parse_call_args()
926        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]:
928    def parse_filter(
929        self, node: t.Optional[nodes.Expr], start_inline: bool = False
930    ) -> t.Optional[nodes.Expr]:
931        while self.stream.current.type == "pipe" or start_inline:
932            if not start_inline:
933                next(self.stream)
934            token = self.stream.expect("name")
935            name = token.value
936            while self.stream.current.type == "dot":
937                next(self.stream)
938                name += "." + self.stream.expect("name").value
939            if self.stream.current.type == "lparen":
940                args, kwargs, dyn_args, dyn_kwargs = self.parse_call_args()
941            else:
942                args = []
943                kwargs = []
944                dyn_args = dyn_kwargs = None
945            node = nodes.Filter(
946                node, name, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno
947            )
948            start_inline = False
949        return node
def parse_test(self, node: jinja2.nodes.Expr) -> jinja2.nodes.Expr:
951    def parse_test(self, node: nodes.Expr) -> nodes.Expr:
952        token = next(self.stream)
953        if self.stream.current.test("name:not"):
954            next(self.stream)
955            negated = True
956        else:
957            negated = False
958        name = self.stream.expect("name").value
959        while self.stream.current.type == "dot":
960            next(self.stream)
961            name += "." + self.stream.expect("name").value
962        dyn_args = dyn_kwargs = None
963        kwargs: t.List[nodes.Keyword] = []
964        if self.stream.current.type == "lparen":
965            args, kwargs, dyn_args, dyn_kwargs = self.parse_call_args()
966        elif self.stream.current.type in {
967            "name",
968            "string",
969            "integer",
970            "float",
971            "lparen",
972            "lbracket",
973            "lbrace",
974        } and not self.stream.current.test_any("name:else", "name:or", "name:and"):
975            if self.stream.current.test("name:is"):
976                self.fail("You cannot chain multiple tests with is")
977            arg_node = self.parse_primary()
978            arg_node = self.parse_postfix(arg_node)
979            args = [arg_node]
980        else:
981            args = []
982        node = nodes.Test(
983            node, name, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno
984        )
985        if negated:
986            node = nodes.Not(node, lineno=token.lineno)
987        return node
def subparse( self, end_tokens: Optional[Tuple[str, ...]] = None) -> List[jinja2.nodes.Node]:
 989    def subparse(
 990        self, end_tokens: t.Optional[t.Tuple[str, ...]] = None
 991    ) -> t.List[nodes.Node]:
 992        body: t.List[nodes.Node] = []
 993        data_buffer: t.List[nodes.Node] = []
 994        add_data = data_buffer.append
 995
 996        if end_tokens is not None:
 997            self._end_token_stack.append(end_tokens)
 998
 999        def flush_data() -> None:
1000            if data_buffer:
1001                lineno = data_buffer[0].lineno
1002                body.append(nodes.Output(data_buffer[:], lineno=lineno))
1003                del data_buffer[:]
1004
1005        try:
1006            while self.stream:
1007                token = self.stream.current
1008                if token.type == "data":
1009                    if token.value:
1010                        add_data(nodes.TemplateData(token.value, lineno=token.lineno))
1011                    next(self.stream)
1012                elif token.type == "variable_begin":
1013                    next(self.stream)
1014                    add_data(self.parse_tuple(with_condexpr=True))
1015                    self.stream.expect("variable_end")
1016                elif token.type == "block_begin":
1017                    flush_data()
1018                    next(self.stream)
1019                    if end_tokens is not None and self.stream.current.test_any(
1020                        *end_tokens
1021                    ):
1022                        return body
1023                    rv = self.parse_statement()
1024                    if isinstance(rv, list):
1025                        body.extend(rv)
1026                    else:
1027                        body.append(rv)
1028                    self.stream.expect("block_end")
1029                else:
1030                    raise AssertionError("internal parsing error")
1031
1032            flush_data()
1033        finally:
1034            if end_tokens is not None:
1035                self._end_token_stack.pop()
1036        return body
def parse(self) -> jinja2.nodes.Template:
1038    def parse(self) -> nodes.Template:
1039        """Parse the whole template into a `Template` node."""
1040        result = nodes.Template(self.subparse(), lineno=1)
1041        result.set_environment(self.environment)
1042        return result

Parse the whole template into a Template node.