You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1041 lines
39KB

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