|
7 | 7 | from __future__ import annotations |
8 | 8 |
|
9 | 9 | import ast |
| 10 | +import sys |
10 | 11 | from dataclasses import dataclass |
11 | 12 | from dataclasses import fields as getfields |
12 | 13 | from enum import IntEnum, auto |
@@ -532,6 +533,20 @@ def iterate(self, *, flat: bool = True) -> Iterator[str | Expr]: |
532 | 533 | yield from _yield(self.orelse, flat=flat, outer_precedence=precedence, is_left=False) |
533 | 534 |
|
534 | 535 |
|
| 536 | +@dataclass(eq=True, slots=True) |
| 537 | +class ExprInterpolation(Expr): |
| 538 | + """Template string interpolation like `{name}`.""" |
| 539 | + |
| 540 | + value: str | Expr |
| 541 | + """Interpolated value.""" |
| 542 | + |
| 543 | + def iterate(self, *, flat: bool = True) -> Iterator[str | Expr]: |
| 544 | + yield "{" |
| 545 | + # Prevent parentheses from being added, avoiding `{(1 + 1)}` |
| 546 | + yield from _yield(self.value, flat=flat, outer_precedence=_OperatorPrecedence.NONE) |
| 547 | + yield "}" |
| 548 | + |
| 549 | + |
535 | 550 | @dataclass(eq=True, slots=True) |
536 | 551 | class ExprJoinedStr(Expr): |
537 | 552 | """Joined strings like `f"a {b} c"`.""" |
@@ -915,6 +930,19 @@ def canonical_path(self) -> str: |
915 | 930 | return self.left.canonical_path |
916 | 931 |
|
917 | 932 |
|
| 933 | +@dataclass(eq=True, slots=True) |
| 934 | +class ExprTemplateStr(Expr): |
| 935 | + """Template strings like `t"a {name}"`.""" |
| 936 | + |
| 937 | + values: Sequence[str | Expr] |
| 938 | + """Joined values.""" |
| 939 | + |
| 940 | + def iterate(self, *, flat: bool = True) -> Iterator[str | Expr]: |
| 941 | + yield "t'" |
| 942 | + yield from _join(self.values, "", flat=flat) |
| 943 | + yield "'" |
| 944 | + |
| 945 | + |
918 | 946 | @dataclass(eq=True, slots=True) |
919 | 947 | class ExprTuple(Expr): |
920 | 948 | """Tuples like `(0, 1, 2)`.""" |
@@ -1369,6 +1397,25 @@ def __call__(self, node: Any, parent: Module | Class, **kwargs: Any) -> Expr: .. |
1369 | 1397 | ast.YieldFrom: _build_yield_from, |
1370 | 1398 | } |
1371 | 1399 |
|
| 1400 | +if sys.version_info >= (3, 14): |
| 1401 | + |
| 1402 | + def _build_interpolation(node: ast.Interpolation, parent: Module | Class, **kwargs: Any) -> Expr: |
| 1403 | + return ExprInterpolation(_build(node.value, parent, **kwargs)) |
| 1404 | + |
| 1405 | + def _build_templatestr( |
| 1406 | + node: ast.TemplateStr, |
| 1407 | + parent: Module | Class, |
| 1408 | + **kwargs: Any, |
| 1409 | + ) -> Expr: |
| 1410 | + return ExprTemplateStr([_build(value, parent, in_joined_str=True, **kwargs) for value in node.values]) |
| 1411 | + |
| 1412 | + _node_map.update( |
| 1413 | + { |
| 1414 | + ast.Interpolation: _build_interpolation, |
| 1415 | + ast.TemplateStr: _build_templatestr, |
| 1416 | + }, |
| 1417 | + ) |
| 1418 | + |
1372 | 1419 |
|
1373 | 1420 | def _build(node: ast.AST, parent: Module | Class, /, **kwargs: Any) -> Expr: |
1374 | 1421 | return _node_map[type(node)](node, parent, **kwargs) |
|
0 commit comments