ruff_python_ast/token/
parentheses.rs1use ruff_text_size::{Ranged, TextRange};
2
3use super::{TokenKind, Tokens};
4use crate::{AnyNodeRef, ExprRef};
5
6pub fn parentheses_iterator<'a>(
14 expr: ExprRef<'a>,
15 parent: Option<AnyNodeRef>,
16 tokens: &'a Tokens,
17) -> impl Iterator<Item = TextRange> + 'a {
18 let after_tokens = if let Some(parent) = parent {
19 let after_tokens = tokens.in_range(TextRange::new(expr.end(), parent.end()));
20
21 if parent.is_arguments()
26 && let Some((last, remaining)) = after_tokens.split_last()
27 && last.kind() == TokenKind::Rpar
28 {
29 remaining
30 } else {
31 after_tokens
32 }
33 } else {
34 tokens.after(expr.end())
35 };
36
37 let right_parens = after_tokens
38 .iter()
39 .filter(|token| !token.kind().is_trivia())
40 .take_while(move |token| token.kind() == TokenKind::Rpar);
41
42 let left_parens = tokens
43 .before(expr.start())
44 .iter()
45 .rev()
46 .filter(|token| !token.kind().is_trivia())
47 .take_while(|token| token.kind() == TokenKind::Lpar);
48
49 right_parens
50 .zip(left_parens)
51 .map(|(right, left)| TextRange::new(left.start(), right.end()))
52}
53
54pub fn parenthesized_range(
57 expr: ExprRef,
58 parent: AnyNodeRef,
59 tokens: &Tokens,
60) -> Option<TextRange> {
61 parentheses_iterator(expr, Some(parent), tokens).last()
62}