Skip to main content

ruff_python_ast/
nodes.rs

1#![allow(clippy::derive_partial_eq_without_eq)]
2
3use crate::AtomicNodeIndex;
4use crate::generated::{
5    ExprBytesLiteral, ExprCall, ExprDict, ExprFString, ExprList, ExprName, ExprSet,
6    ExprStringLiteral, ExprTString, ExprTuple, PatternMatchAs, PatternMatchOr, StmtClassDef,
7};
8use std::borrow::Cow;
9use std::fmt;
10use std::fmt::Debug;
11use std::iter::FusedIterator;
12use std::ops::{Deref, DerefMut};
13use std::slice::{Iter, IterMut};
14use std::sync::OnceLock;
15
16use bitflags::bitflags;
17use thin_vec::ThinVec;
18
19use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
20
21use crate::str_prefix::{
22    AnyStringPrefix, ByteStringPrefix, FStringPrefix, StringLiteralPrefix, TStringPrefix,
23};
24use crate::{
25    Expr, ExprRef, InterpolatedStringElement, LiteralExpressionRef, OperatorPrecedence, Pattern,
26    Stmt, TypeParam, int,
27    name::Name,
28    str::{Quote, TripleQuotes},
29};
30
31impl StmtClassDef {
32    /// Return an iterator over the bases of the class.
33    pub fn bases(&self) -> &[Expr] {
34        match &self.arguments {
35            Some(arguments) => &arguments.args,
36            None => &[],
37        }
38    }
39
40    /// Return an iterator over the metaclass keywords of the class.
41    pub fn keywords(&self) -> &[Keyword] {
42        match &self.arguments {
43            Some(arguments) => &arguments.keywords,
44            None => &[],
45        }
46    }
47}
48
49#[derive(Clone, Debug, PartialEq)]
50#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
51pub struct ElifElseClause {
52    pub range: TextRange,
53    pub node_index: AtomicNodeIndex,
54    pub test: Option<Expr>,
55    pub body: Suite,
56}
57
58impl Expr {
59    /// Returns `true` if the expression is a literal expression.
60    ///
61    /// A literal expression is either a string literal, bytes literal,
62    /// integer, float, complex number, boolean, `None`, or ellipsis (`...`).
63    pub fn is_literal_expr(&self) -> bool {
64        matches!(
65            self,
66            Expr::StringLiteral(_)
67                | Expr::BytesLiteral(_)
68                | Expr::NumberLiteral(_)
69                | Expr::BooleanLiteral(_)
70                | Expr::NoneLiteral(_)
71                | Expr::EllipsisLiteral(_)
72        )
73    }
74
75    /// Returns [`LiteralExpressionRef`] if the expression is a literal expression.
76    pub fn as_literal_expr(&self) -> Option<LiteralExpressionRef<'_>> {
77        match self {
78            Expr::StringLiteral(expr) => Some(LiteralExpressionRef::StringLiteral(expr)),
79            Expr::BytesLiteral(expr) => Some(LiteralExpressionRef::BytesLiteral(expr)),
80            Expr::NumberLiteral(expr) => Some(LiteralExpressionRef::NumberLiteral(expr)),
81            Expr::BooleanLiteral(expr) => Some(LiteralExpressionRef::BooleanLiteral(expr)),
82            Expr::NoneLiteral(expr) => Some(LiteralExpressionRef::NoneLiteral(expr)),
83            Expr::EllipsisLiteral(expr) => Some(LiteralExpressionRef::EllipsisLiteral(expr)),
84            _ => None,
85        }
86    }
87
88    /// Return the value expression after peeling off any nested named expressions.
89    ///
90    /// For example, this returns the `x` expression for both `x` and `(y := x)`.
91    pub fn expression_value(&self) -> &Self {
92        let mut expr = self;
93        while let Expr::Named(named) = expr {
94            expr = &named.value;
95        }
96        expr
97    }
98
99    /// Return the [`OperatorPrecedence`] of this expression
100    pub fn precedence(&self) -> OperatorPrecedence {
101        OperatorPrecedence::from(self)
102    }
103}
104
105impl ExprRef<'_> {
106    /// See [`Expr::is_literal_expr`].
107    pub fn is_literal_expr(&self) -> bool {
108        matches!(
109            self,
110            ExprRef::StringLiteral(_)
111                | ExprRef::BytesLiteral(_)
112                | ExprRef::NumberLiteral(_)
113                | ExprRef::BooleanLiteral(_)
114                | ExprRef::NoneLiteral(_)
115                | ExprRef::EllipsisLiteral(_)
116        )
117    }
118
119    pub fn precedence(&self) -> OperatorPrecedence {
120        OperatorPrecedence::from(*self)
121    }
122}
123
124/// Represents an item in a [dictionary literal display][1].
125///
126/// Consider the following Python dictionary literal:
127/// ```python
128/// {key1: value1, **other_dictionary}
129/// ```
130///
131/// In our AST, this would be represented using an `ExprDict` node containing
132/// two `DictItem` nodes inside it:
133/// ```ignore
134/// [
135///     DictItem {
136///         key: Some(Expr::Name(ExprName { id: "key1" })),
137///         value: Expr::Name(ExprName { id: "value1" }),
138///     },
139///     DictItem {
140///         key: None,
141///         value: Expr::Name(ExprName { id: "other_dictionary" }),
142///     }
143/// ]
144/// ```
145///
146/// [1]: https://docs.python.org/3/reference/expressions.html#displays-for-lists-sets-and-dictionaries
147#[derive(Debug, Clone, PartialEq)]
148#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
149pub struct DictItem {
150    pub key: Option<Expr>,
151    pub value: Expr,
152}
153
154impl DictItem {
155    fn key(&self) -> Option<&Expr> {
156        self.key.as_ref()
157    }
158
159    fn value(&self) -> &Expr {
160        &self.value
161    }
162}
163
164impl Ranged for DictItem {
165    fn range(&self) -> TextRange {
166        TextRange::new(
167            self.key.as_ref().map_or(self.value.start(), Ranged::start),
168            self.value.end(),
169        )
170    }
171}
172
173impl ExprDict {
174    /// Returns an `Iterator` over the AST nodes representing the
175    /// dictionary's keys.
176    pub fn iter_keys(&self) -> DictKeyIterator<'_> {
177        DictKeyIterator::new(&self.items)
178    }
179
180    /// Returns an `Iterator` over the AST nodes representing the
181    /// dictionary's values.
182    pub fn iter_values(&self) -> DictValueIterator<'_> {
183        DictValueIterator::new(&self.items)
184    }
185
186    /// Returns the AST node representing the *n*th key of this
187    /// dictionary.
188    ///
189    /// Panics: If the index `n` is out of bounds.
190    pub fn key(&self, n: usize) -> Option<&Expr> {
191        self.items[n].key()
192    }
193
194    /// Returns the AST node representing the *n*th value of this
195    /// dictionary.
196    ///
197    /// Panics: If the index `n` is out of bounds.
198    pub fn value(&self, n: usize) -> &Expr {
199        self.items[n].value()
200    }
201
202    pub fn iter(&self) -> std::slice::Iter<'_, DictItem> {
203        self.items.iter()
204    }
205
206    pub fn len(&self) -> usize {
207        self.items.len()
208    }
209
210    pub fn is_empty(&self) -> bool {
211        self.items.is_empty()
212    }
213}
214
215impl<'a> IntoIterator for &'a ExprDict {
216    type IntoIter = std::slice::Iter<'a, DictItem>;
217    type Item = &'a DictItem;
218
219    fn into_iter(self) -> Self::IntoIter {
220        self.iter()
221    }
222}
223
224#[derive(Debug, Clone)]
225pub struct DictKeyIterator<'a> {
226    items: Iter<'a, DictItem>,
227}
228
229impl<'a> DictKeyIterator<'a> {
230    fn new(items: &'a [DictItem]) -> Self {
231        Self {
232            items: items.iter(),
233        }
234    }
235
236    pub fn is_empty(&self) -> bool {
237        self.len() == 0
238    }
239}
240
241impl<'a> Iterator for DictKeyIterator<'a> {
242    type Item = Option<&'a Expr>;
243
244    fn next(&mut self) -> Option<Self::Item> {
245        self.items.next().map(DictItem::key)
246    }
247
248    fn last(mut self) -> Option<Self::Item> {
249        self.next_back()
250    }
251
252    fn size_hint(&self) -> (usize, Option<usize>) {
253        self.items.size_hint()
254    }
255}
256
257impl DoubleEndedIterator for DictKeyIterator<'_> {
258    fn next_back(&mut self) -> Option<Self::Item> {
259        self.items.next_back().map(DictItem::key)
260    }
261}
262
263impl FusedIterator for DictKeyIterator<'_> {}
264impl ExactSizeIterator for DictKeyIterator<'_> {}
265
266#[derive(Debug, Clone)]
267pub struct DictValueIterator<'a> {
268    items: Iter<'a, DictItem>,
269}
270
271impl<'a> DictValueIterator<'a> {
272    fn new(items: &'a [DictItem]) -> Self {
273        Self {
274            items: items.iter(),
275        }
276    }
277
278    pub fn is_empty(&self) -> bool {
279        self.len() == 0
280    }
281}
282
283impl<'a> Iterator for DictValueIterator<'a> {
284    type Item = &'a Expr;
285
286    fn next(&mut self) -> Option<Self::Item> {
287        self.items.next().map(DictItem::value)
288    }
289
290    fn last(mut self) -> Option<Self::Item> {
291        self.next_back()
292    }
293
294    fn size_hint(&self) -> (usize, Option<usize>) {
295        self.items.size_hint()
296    }
297}
298
299impl DoubleEndedIterator for DictValueIterator<'_> {
300    fn next_back(&mut self) -> Option<Self::Item> {
301        self.items.next_back().map(DictItem::value)
302    }
303}
304
305impl FusedIterator for DictValueIterator<'_> {}
306impl ExactSizeIterator for DictValueIterator<'_> {}
307
308impl ExprSet {
309    pub fn iter(&self) -> std::slice::Iter<'_, Expr> {
310        self.elts.iter()
311    }
312
313    pub fn len(&self) -> usize {
314        self.elts.len()
315    }
316
317    pub fn is_empty(&self) -> bool {
318        self.elts.is_empty()
319    }
320}
321
322impl<'a> IntoIterator for &'a ExprSet {
323    type IntoIter = std::slice::Iter<'a, Expr>;
324    type Item = &'a Expr;
325
326    fn into_iter(self) -> Self::IntoIter {
327        self.iter()
328    }
329}
330
331#[derive(Clone, Debug, PartialEq)]
332#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
333pub struct InterpolatedStringFormatSpec {
334    pub range: TextRange,
335    pub node_index: AtomicNodeIndex,
336    pub elements: InterpolatedStringElements,
337}
338
339/// See also [FormattedValue](https://docs.python.org/3/library/ast.html#ast.FormattedValue)
340#[derive(Clone, Debug, PartialEq)]
341#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
342pub struct InterpolatedElement {
343    pub range: TextRange,
344    pub node_index: AtomicNodeIndex,
345    pub expression: Box<Expr>,
346    pub debug_text: Option<DebugText>,
347    pub conversion: ConversionFlag,
348    pub format_spec: Option<Box<InterpolatedStringFormatSpec>>,
349}
350
351/// An `FStringLiteralElement` with an empty `value` is an invalid f-string element.
352#[derive(Clone, Debug, PartialEq)]
353#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
354pub struct InterpolatedStringLiteralElement {
355    pub range: TextRange,
356    pub node_index: AtomicNodeIndex,
357    pub value: Box<str>,
358}
359
360impl InterpolatedStringLiteralElement {
361    pub fn is_valid(&self) -> bool {
362        !self.value.is_empty()
363    }
364}
365
366impl Deref for InterpolatedStringLiteralElement {
367    type Target = str;
368
369    fn deref(&self) -> &Self::Target {
370        &self.value
371    }
372}
373
374/// Transforms a value prior to formatting it.
375#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, is_macro::Is)]
376#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
377#[repr(i8)]
378#[expect(clippy::cast_possible_wrap)]
379pub enum ConversionFlag {
380    /// No conversion
381    None = -1, // CPython uses -1
382    /// Converts by calling `str(<value>)`.
383    Str = b's' as i8,
384    /// Converts by calling `ascii(<value>)`.
385    Ascii = b'a' as i8,
386    /// Converts by calling `repr(<value>)`.
387    Repr = b'r' as i8,
388}
389
390impl ConversionFlag {
391    pub fn to_byte(&self) -> Option<u8> {
392        match self {
393            Self::None => None,
394            flag => Some(*flag as u8),
395        }
396    }
397    pub fn to_char(&self) -> Option<char> {
398        Some(self.to_byte()? as char)
399    }
400}
401
402/// The debug text of a self-documenting f-string expression (e.g., `f"{x=}"`).
403///
404/// Stores the concatenation of leading text, expression source, and trailing text as a single
405/// [`CompactString`], with byte offsets to split them. The offsets are needed because the leading
406/// and trailing portions can contain non-whitespace characters (grouping parentheses, comments in
407/// triple-quoted f-strings) that cannot be distinguished from expression content by scanning.
408///
409/// [`CompactString`]: compact_str::CompactString
410#[derive(Clone, PartialEq, Eq, Hash)]
411#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
412pub struct DebugText {
413    /// The full text between the `{` and the conversion / `format_spec` / `}`.
414    text: compact_str::CompactString,
415    /// Byte offset where the expression source begins.
416    expression_start: u32,
417    /// Byte offset where the expression source ends.
418    expression_end: u32,
419}
420
421impl std::fmt::Debug for DebugText {
422    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
423        f.debug_struct("DebugText")
424            .field("leading", &self.leading())
425            .field("expression", &self.expression())
426            .field("trailing", &self.trailing())
427            .finish()
428    }
429}
430
431impl DebugText {
432    pub fn new(leading: &str, expression: &str, trailing: &str) -> Self {
433        let expression_start = leading.text_len().to_u32();
434        let expression_end = expression_start + expression.text_len().to_u32();
435        let mut buf = compact_str::CompactString::with_capacity(
436            leading.len() + expression.len() + trailing.len(),
437        );
438        buf.push_str(leading);
439        buf.push_str(expression);
440        buf.push_str(trailing);
441        Self {
442            text: buf,
443            expression_start,
444            expression_end,
445        }
446    }
447
448    /// The full debug text between the `{` and the conversion / `format_spec` / `}`.
449    pub fn as_str(&self) -> &str {
450        &self.text
451    }
452
453    /// The text between the `{` and the expression node.
454    pub fn leading(&self) -> &str {
455        &self.text[..self.expression_start as usize]
456    }
457
458    /// The source text of the expression (e.g., `0x0` in `f"{0x0=}"`).
459    pub fn expression(&self) -> &str {
460        &self.text[self.expression_start as usize..self.expression_end as usize]
461    }
462
463    /// The text between the expression and the conversion, the `format_spec`, or the `}`.
464    pub fn trailing(&self) -> &str {
465        &self.text[self.expression_end as usize..]
466    }
467}
468
469impl ExprFString {
470    /// Returns the single [`FString`] if the f-string isn't implicitly concatenated, [`None`]
471    /// otherwise.
472    pub const fn as_single_part_fstring(&self) -> Option<&FString> {
473        match &self.value.inner {
474            FStringValueInner::Single(FStringPart::FString(fstring)) => Some(fstring),
475            _ => None,
476        }
477    }
478}
479
480/// The value representing an [`ExprFString`].
481#[derive(Clone, Debug, PartialEq)]
482#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
483pub struct FStringValue {
484    inner: FStringValueInner,
485}
486
487impl FStringValue {
488    /// Creates a new f-string literal with a single [`FString`] part.
489    pub fn single(value: FString) -> Self {
490        Self {
491            inner: FStringValueInner::Single(FStringPart::FString(value)),
492        }
493    }
494
495    /// Creates a new f-string with the given values that represents an implicitly
496    /// concatenated f-string.
497    ///
498    /// # Panics
499    ///
500    /// Panics if `values` has less than 2 elements.
501    /// Use [`FStringValue::single`] instead.
502    pub fn concatenated(values: Vec<FStringPart>) -> Self {
503        assert!(
504            values.len() > 1,
505            "Use `FStringValue::single` to create single-part f-strings"
506        );
507        Self {
508            inner: FStringValueInner::Concatenated(values),
509        }
510    }
511
512    /// Returns `true` if the f-string is implicitly concatenated, `false` otherwise.
513    pub fn is_implicit_concatenated(&self) -> bool {
514        matches!(self.inner, FStringValueInner::Concatenated(_))
515    }
516
517    /// Returns a slice of all the [`FStringPart`]s contained in this value.
518    pub fn as_slice(&self) -> &[FStringPart] {
519        match &self.inner {
520            FStringValueInner::Single(part) => std::slice::from_ref(part),
521            FStringValueInner::Concatenated(parts) => parts,
522        }
523    }
524
525    /// Returns a mutable slice of all the [`FStringPart`]s contained in this value.
526    fn as_mut_slice(&mut self) -> &mut [FStringPart] {
527        match &mut self.inner {
528            FStringValueInner::Single(part) => std::slice::from_mut(part),
529            FStringValueInner::Concatenated(parts) => parts,
530        }
531    }
532
533    /// Returns an iterator over all the [`FStringPart`]s contained in this value.
534    pub fn iter(&self) -> Iter<'_, FStringPart> {
535        self.as_slice().iter()
536    }
537
538    /// Returns an iterator over all the [`FStringPart`]s contained in this value
539    /// that allows modification.
540    pub fn iter_mut(&mut self) -> IterMut<'_, FStringPart> {
541        self.as_mut_slice().iter_mut()
542    }
543
544    /// Returns an iterator over the [`StringLiteral`] parts contained in this value.
545    ///
546    /// Note that this doesn't recurse into the f-string parts. For example,
547    ///
548    /// ```python
549    /// "foo" f"bar {x}" "baz" f"qux"
550    /// ```
551    ///
552    /// Here, the string literal parts returned would be `"foo"` and `"baz"`.
553    pub fn literals(&self) -> impl Iterator<Item = &StringLiteral> {
554        self.iter().filter_map(|part| part.as_literal())
555    }
556
557    /// Returns an iterator over the [`FString`] parts contained in this value.
558    ///
559    /// Note that this doesn't recurse into the f-string parts. For example,
560    ///
561    /// ```python
562    /// "foo" f"bar {x}" "baz" f"qux"
563    /// ```
564    ///
565    /// Here, the f-string parts returned would be `f"bar {x}"` and `f"qux"`.
566    pub fn f_strings(&self) -> impl Iterator<Item = &FString> {
567        self.iter().filter_map(|part| part.as_f_string())
568    }
569
570    /// Returns an iterator over all the [`InterpolatedStringElement`] contained in this value.
571    ///
572    /// An f-string element is what makes up an [`FString`] i.e., it is either a
573    /// string literal or an expression. In the following example,
574    ///
575    /// ```python
576    /// "foo" f"bar {x}" "baz" f"qux"
577    /// ```
578    ///
579    /// The f-string elements returned would be string literal (`"bar "`),
580    /// expression (`x`) and string literal (`"qux"`).
581    pub fn elements(&self) -> impl Iterator<Item = &InterpolatedStringElement> {
582        self.f_strings().flat_map(|fstring| fstring.elements.iter())
583    }
584
585    /// Returns `true` if the node represents an empty f-string literal.
586    ///
587    /// Note that a [`FStringValue`] node will always have >= 1 [`FStringPart`]s inside it.
588    /// This method checks whether the value of the concatenated parts is equal to the empty
589    /// f-string, not whether the f-string has 0 parts inside it.
590    pub fn is_empty_literal(&self) -> bool {
591        match &self.inner {
592            FStringValueInner::Single(fstring_part) => fstring_part.is_empty_literal(),
593            FStringValueInner::Concatenated(fstring_parts) => {
594                fstring_parts.iter().all(FStringPart::is_empty_literal)
595            }
596        }
597    }
598}
599
600impl<'a> IntoIterator for &'a FStringValue {
601    type Item = &'a FStringPart;
602    type IntoIter = Iter<'a, FStringPart>;
603
604    fn into_iter(self) -> Self::IntoIter {
605        self.iter()
606    }
607}
608
609impl<'a> IntoIterator for &'a mut FStringValue {
610    type Item = &'a mut FStringPart;
611    type IntoIter = IterMut<'a, FStringPart>;
612    fn into_iter(self) -> Self::IntoIter {
613        self.iter_mut()
614    }
615}
616
617/// An internal representation of [`FStringValue`].
618#[derive(Clone, Debug, PartialEq)]
619#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
620enum FStringValueInner {
621    /// A single f-string i.e., `f"foo"`.
622    ///
623    /// This is always going to be `FStringPart::FString` variant which is
624    /// maintained by the `FStringValue::single` constructor.
625    Single(FStringPart),
626
627    /// An implicitly concatenated f-string i.e., `"foo" f"bar {x}"`.
628    Concatenated(Vec<FStringPart>),
629}
630
631/// An f-string part which is either a string literal or an f-string.
632#[derive(Clone, Debug, PartialEq, is_macro::Is)]
633#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
634pub enum FStringPart {
635    Literal(StringLiteral),
636    FString(FString),
637}
638
639impl FStringPart {
640    pub fn quote_style(&self) -> Quote {
641        match self {
642            Self::Literal(string_literal) => string_literal.flags.quote_style(),
643            Self::FString(f_string) => f_string.flags.quote_style(),
644        }
645    }
646
647    pub fn is_empty_literal(&self) -> bool {
648        match &self {
649            FStringPart::Literal(string_literal) => string_literal.value.is_empty(),
650            FStringPart::FString(f_string) => f_string.elements.is_empty(),
651        }
652    }
653}
654
655impl Ranged for FStringPart {
656    fn range(&self) -> TextRange {
657        match self {
658            FStringPart::Literal(string_literal) => string_literal.range(),
659            FStringPart::FString(f_string) => f_string.range(),
660        }
661    }
662}
663
664impl ExprTString {
665    /// Returns the single [`TString`] if the t-string isn't implicitly concatenated, [`None`]
666    /// otherwise.
667    pub const fn as_single_part_tstring(&self) -> Option<&TString> {
668        match &self.value.inner {
669            TStringValueInner::Single(tstring) => Some(tstring),
670            TStringValueInner::Concatenated(_) => None,
671        }
672    }
673}
674
675/// The value representing an [`ExprTString`].
676#[derive(Clone, Debug, PartialEq)]
677#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
678pub struct TStringValue {
679    inner: TStringValueInner,
680}
681
682impl TStringValue {
683    /// Creates a new t-string literal with a single [`TString`] part.
684    pub fn single(value: TString) -> Self {
685        Self {
686            inner: TStringValueInner::Single(value),
687        }
688    }
689
690    /// Creates a new t-string with the given values that represents an implicitly
691    /// concatenated t-string.
692    ///
693    /// # Panics
694    ///
695    /// Panics if `values` has less than 2 elements.
696    /// Use [`TStringValue::single`] instead.
697    pub fn concatenated(values: Vec<TString>) -> Self {
698        assert!(
699            values.len() > 1,
700            "Use `TStringValue::single` to create single-part t-strings"
701        );
702        Self {
703            inner: TStringValueInner::Concatenated(values),
704        }
705    }
706
707    /// Returns `true` if the t-string is implicitly concatenated, `false` otherwise.
708    pub fn is_implicit_concatenated(&self) -> bool {
709        matches!(self.inner, TStringValueInner::Concatenated(_))
710    }
711
712    /// Returns a slice of all the [`TString`]s contained in this value.
713    pub fn as_slice(&self) -> &[TString] {
714        match &self.inner {
715            TStringValueInner::Single(part) => std::slice::from_ref(part),
716            TStringValueInner::Concatenated(parts) => parts,
717        }
718    }
719
720    /// Returns a mutable slice of all the [`TString`]s contained in this value.
721    fn as_mut_slice(&mut self) -> &mut [TString] {
722        match &mut self.inner {
723            TStringValueInner::Single(part) => std::slice::from_mut(part),
724            TStringValueInner::Concatenated(parts) => parts,
725        }
726    }
727
728    /// Returns an iterator over all the [`TString`]s contained in this value.
729    pub fn iter(&self) -> Iter<'_, TString> {
730        self.as_slice().iter()
731    }
732
733    /// Returns an iterator over all the [`TString`]s contained in this value
734    /// that allows modification.
735    pub fn iter_mut(&mut self) -> IterMut<'_, TString> {
736        self.as_mut_slice().iter_mut()
737    }
738
739    /// Returns an iterator over all the [`InterpolatedStringElement`] contained in this value.
740    ///
741    /// An interpolated string element is what makes up an [`TString`] i.e., it is either a
742    /// string literal or an interpolation. In the following example,
743    ///
744    /// ```python
745    /// t"foo" t"bar {x}" t"baz" t"qux"
746    /// ```
747    ///
748    /// The interpolated string elements returned would be string literal (`"bar "`),
749    /// interpolation (`x`) and string literal (`"qux"`).
750    pub fn elements(&self) -> impl Iterator<Item = &InterpolatedStringElement> {
751        self.iter().flat_map(|tstring| tstring.elements.iter())
752    }
753
754    /// Returns `true` if the node represents an empty t-string in the
755    /// sense that `__iter__` returns an empty iterable.
756    ///
757    /// Beware that empty t-strings are still truthy, i.e. `bool(t"") == True`.
758    ///
759    /// Note that a [`TStringValue`] node will always contain at least one
760    /// [`TString`] node. This method checks whether each of the constituent
761    /// t-strings (in an implicitly concatenated t-string) are empty
762    /// in the above sense.
763    pub fn is_empty_iterable(&self) -> bool {
764        match &self.inner {
765            TStringValueInner::Single(tstring) => tstring.is_empty(),
766            TStringValueInner::Concatenated(tstrings) => tstrings.iter().all(TString::is_empty),
767        }
768    }
769}
770
771impl<'a> IntoIterator for &'a TStringValue {
772    type Item = &'a TString;
773    type IntoIter = Iter<'a, TString>;
774
775    fn into_iter(self) -> Self::IntoIter {
776        self.iter()
777    }
778}
779
780impl<'a> IntoIterator for &'a mut TStringValue {
781    type Item = &'a mut TString;
782    type IntoIter = IterMut<'a, TString>;
783    fn into_iter(self) -> Self::IntoIter {
784        self.iter_mut()
785    }
786}
787
788/// An internal representation of [`TStringValue`].
789#[derive(Clone, Debug, PartialEq)]
790#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
791enum TStringValueInner {
792    /// A single t-string i.e., `t"foo"`.
793    Single(TString),
794
795    /// An implicitly concatenated t-string i.e., `t"foo" t"bar {x}"`.
796    Concatenated(Vec<TString>),
797}
798
799pub trait StringFlags: Copy {
800    /// Does the string use single or double quotes in its opener and closer?
801    fn quote_style(self) -> Quote;
802
803    fn triple_quotes(self) -> TripleQuotes;
804
805    fn prefix(self) -> AnyStringPrefix;
806
807    fn is_unclosed(self) -> bool;
808
809    /// Is the string triple-quoted, i.e.,
810    /// does it begin and end with three consecutive quote characters?
811    fn is_triple_quoted(self) -> bool {
812        self.triple_quotes().is_yes()
813    }
814
815    /// A `str` representation of the quotes used to start and close.
816    /// This does not include any prefixes the string has in its opener.
817    fn quote_str(self) -> &'static str {
818        match (self.triple_quotes(), self.quote_style()) {
819            (TripleQuotes::Yes, Quote::Single) => "'''",
820            (TripleQuotes::Yes, Quote::Double) => r#"""""#,
821            (TripleQuotes::No, Quote::Single) => "'",
822            (TripleQuotes::No, Quote::Double) => "\"",
823        }
824    }
825
826    /// The length of the quotes used to start and close the string.
827    /// This does not include the length of any prefixes the string has
828    /// in its opener.
829    fn quote_len(self) -> TextSize {
830        if self.is_triple_quoted() {
831            TextSize::new(3)
832        } else {
833            TextSize::new(1)
834        }
835    }
836
837    /// The total length of the string's opener,
838    /// i.e., the length of the prefixes plus the length
839    /// of the quotes used to open the string.
840    fn opener_len(self) -> TextSize {
841        self.prefix().text_len() + self.quote_len()
842    }
843
844    /// The total length of the string's closer.
845    /// This is always equal to `self.quote_len()`, except when the string is unclosed,
846    /// in which case the length is zero.
847    fn closer_len(self) -> TextSize {
848        if self.is_unclosed() {
849            TextSize::default()
850        } else {
851            self.quote_len()
852        }
853    }
854
855    fn as_any_string_flags(self) -> AnyStringFlags {
856        AnyStringFlags::new(self.prefix(), self.quote_style(), self.triple_quotes())
857            .with_unclosed(self.is_unclosed())
858    }
859
860    fn display_contents(self, contents: &str) -> DisplayFlags<'_> {
861        DisplayFlags {
862            flags: self.as_any_string_flags(),
863            contents,
864        }
865    }
866}
867
868pub struct DisplayFlags<'a> {
869    flags: AnyStringFlags,
870    contents: &'a str,
871}
872
873impl std::fmt::Display for DisplayFlags<'_> {
874    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
875        write!(
876            f,
877            "{prefix}{quote}{contents}{quote}",
878            prefix = self.flags.prefix(),
879            quote = self.flags.quote_str(),
880            contents = self.contents
881        )
882    }
883}
884
885bitflags! {
886    #[derive(Default, Copy, Clone, PartialEq, Eq, Hash)]
887    struct InterpolatedStringFlagsInner: u8 {
888        /// The f-string uses double quotes (`"`) for its opener and closer.
889        /// If this flag is not set, the f-string uses single quotes (`'`)
890        /// for its opener and closer.
891        const DOUBLE = 1 << 0;
892
893        /// The f-string is triple-quoted:
894        /// it begins and ends with three consecutive quote characters.
895        /// For example: `f"""{bar}"""`.
896        const TRIPLE_QUOTED = 1 << 1;
897
898        /// The f-string has an `r` prefix, meaning it is a raw f-string
899        /// with a lowercase 'r'. For example: `rf"{bar}"`
900        const R_PREFIX_LOWER = 1 << 2;
901
902        /// The f-string has an `R` prefix, meaning it is a raw f-string
903        /// with an uppercase 'r'. For example: `Rf"{bar}"`.
904        /// See https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#r-strings-and-r-strings
905        /// for why we track the casing of the `r` prefix,
906        /// but not for any other prefix
907        const R_PREFIX_UPPER = 1 << 3;
908
909        /// The f-string is unclosed, meaning it is missing a closing quote.
910        /// For example: `f"{bar`
911        const UNCLOSED = 1 << 4;
912    }
913}
914
915#[cfg(feature = "get-size")]
916impl get_size2::GetSize for InterpolatedStringFlagsInner {}
917
918/// Flags that can be queried to obtain information
919/// regarding the prefixes and quotes used for an f-string.
920///
921/// Note: This is identical to [`TStringFlags`] except that
922/// the implementation of the `prefix` method of the
923/// [`StringFlags`] trait returns a variant of
924/// `AnyStringPrefix::Format`.
925///
926/// ## Notes on usage
927///
928/// If you're using a `Generator` from the `ruff_python_codegen` crate to generate a lint-rule fix
929/// from an existing f-string literal, consider passing along the [`FString::flags`] field. If you
930/// don't have an existing literal but have a `Checker` from the `ruff_linter` crate available,
931/// consider using `Checker::default_fstring_flags` to create instances of this struct; this method
932/// will properly handle nested f-strings. For usage that doesn't fit into one of these categories,
933/// the public constructor [`FStringFlags::empty`] can be used.
934#[derive(Copy, Clone, Eq, PartialEq, Hash)]
935#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
936pub struct FStringFlags(InterpolatedStringFlagsInner);
937
938impl FStringFlags {
939    /// Construct a new [`FStringFlags`] with **no flags set**.
940    ///
941    /// See [`FStringFlags::with_quote_style`], [`FStringFlags::with_triple_quotes`], and
942    /// [`FStringFlags::with_prefix`] for ways of setting the quote style (single or double),
943    /// enabling triple quotes, and adding prefixes (such as `r`), respectively.
944    ///
945    /// See the documentation for [`FStringFlags`] for additional caveats on this constructor, and
946    /// situations in which alternative ways to construct this struct should be used, especially
947    /// when writing lint rules.
948    pub fn empty() -> Self {
949        Self(InterpolatedStringFlagsInner::empty())
950    }
951
952    #[must_use]
953    pub fn with_quote_style(mut self, quote_style: Quote) -> Self {
954        self.0.set(
955            InterpolatedStringFlagsInner::DOUBLE,
956            quote_style.is_double(),
957        );
958        self
959    }
960
961    #[must_use]
962    pub fn with_triple_quotes(mut self, triple_quotes: TripleQuotes) -> Self {
963        self.0.set(
964            InterpolatedStringFlagsInner::TRIPLE_QUOTED,
965            triple_quotes.is_yes(),
966        );
967        self
968    }
969
970    #[must_use]
971    pub fn with_unclosed(mut self, unclosed: bool) -> Self {
972        self.0.set(InterpolatedStringFlagsInner::UNCLOSED, unclosed);
973        self
974    }
975
976    #[must_use]
977    pub fn with_prefix(mut self, prefix: FStringPrefix) -> Self {
978        match prefix {
979            FStringPrefix::Regular => Self(
980                self.0
981                    - InterpolatedStringFlagsInner::R_PREFIX_LOWER
982                    - InterpolatedStringFlagsInner::R_PREFIX_UPPER,
983            ),
984            FStringPrefix::Raw { uppercase_r } => {
985                self.0
986                    .set(InterpolatedStringFlagsInner::R_PREFIX_UPPER, uppercase_r);
987                self.0
988                    .set(InterpolatedStringFlagsInner::R_PREFIX_LOWER, !uppercase_r);
989                self
990            }
991        }
992    }
993
994    pub const fn prefix(self) -> FStringPrefix {
995        if self
996            .0
997            .contains(InterpolatedStringFlagsInner::R_PREFIX_LOWER)
998        {
999            debug_assert!(
1000                !self
1001                    .0
1002                    .contains(InterpolatedStringFlagsInner::R_PREFIX_UPPER)
1003            );
1004            FStringPrefix::Raw { uppercase_r: false }
1005        } else if self
1006            .0
1007            .contains(InterpolatedStringFlagsInner::R_PREFIX_UPPER)
1008        {
1009            FStringPrefix::Raw { uppercase_r: true }
1010        } else {
1011            FStringPrefix::Regular
1012        }
1013    }
1014}
1015
1016// TODO(dylan): the documentation about using
1017// `Checker::default_tstring_flags` is not yet
1018// correct. This method does not yet exist because
1019// introducing it would emit a dead code warning
1020// until we call it in lint rules.
1021/// Flags that can be queried to obtain information
1022/// regarding the prefixes and quotes used for an f-string.
1023///
1024/// Note: This is identical to [`FStringFlags`] except that
1025/// the implementation of the `prefix` method of the
1026/// [`StringFlags`] trait returns a variant of
1027/// `AnyStringPrefix::Template`.
1028///
1029/// ## Notes on usage
1030///
1031/// If you're using a `Generator` from the `ruff_python_codegen` crate to generate a lint-rule fix
1032/// from an existing t-string literal, consider passing along the [`FString::flags`] field. If you
1033/// don't have an existing literal but have a `Checker` from the `ruff_linter` crate available,
1034/// consider using `Checker::default_tstring_flags` to create instances of this struct; this method
1035/// will properly handle nested t-strings. For usage that doesn't fit into one of these categories,
1036/// the public constructor [`TStringFlags::empty`] can be used.
1037#[derive(Copy, Clone, Eq, PartialEq, Hash)]
1038#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1039pub struct TStringFlags(InterpolatedStringFlagsInner);
1040
1041impl TStringFlags {
1042    /// Construct a new [`TStringFlags`] with **no flags set**.
1043    ///
1044    /// See [`TStringFlags::with_quote_style`], [`TStringFlags::with_triple_quotes`], and
1045    /// [`TStringFlags::with_prefix`] for ways of setting the quote style (single or double),
1046    /// enabling triple quotes, and adding prefixes (such as `r`), respectively.
1047    ///
1048    /// See the documentation for [`TStringFlags`] for additional caveats on this constructor, and
1049    /// situations in which alternative ways to construct this struct should be used, especially
1050    /// when writing lint rules.
1051    pub fn empty() -> Self {
1052        Self(InterpolatedStringFlagsInner::empty())
1053    }
1054
1055    #[must_use]
1056    pub fn with_quote_style(mut self, quote_style: Quote) -> Self {
1057        self.0.set(
1058            InterpolatedStringFlagsInner::DOUBLE,
1059            quote_style.is_double(),
1060        );
1061        self
1062    }
1063
1064    #[must_use]
1065    pub fn with_triple_quotes(mut self, triple_quotes: TripleQuotes) -> Self {
1066        self.0.set(
1067            InterpolatedStringFlagsInner::TRIPLE_QUOTED,
1068            triple_quotes.is_yes(),
1069        );
1070        self
1071    }
1072
1073    #[must_use]
1074    pub fn with_unclosed(mut self, unclosed: bool) -> Self {
1075        self.0.set(InterpolatedStringFlagsInner::UNCLOSED, unclosed);
1076        self
1077    }
1078
1079    #[must_use]
1080    pub fn with_prefix(mut self, prefix: TStringPrefix) -> Self {
1081        match prefix {
1082            TStringPrefix::Regular => Self(
1083                self.0
1084                    - InterpolatedStringFlagsInner::R_PREFIX_LOWER
1085                    - InterpolatedStringFlagsInner::R_PREFIX_UPPER,
1086            ),
1087            TStringPrefix::Raw { uppercase_r } => {
1088                self.0
1089                    .set(InterpolatedStringFlagsInner::R_PREFIX_UPPER, uppercase_r);
1090                self.0
1091                    .set(InterpolatedStringFlagsInner::R_PREFIX_LOWER, !uppercase_r);
1092                self
1093            }
1094        }
1095    }
1096
1097    pub const fn prefix(self) -> TStringPrefix {
1098        if self
1099            .0
1100            .contains(InterpolatedStringFlagsInner::R_PREFIX_LOWER)
1101        {
1102            debug_assert!(
1103                !self
1104                    .0
1105                    .contains(InterpolatedStringFlagsInner::R_PREFIX_UPPER)
1106            );
1107            TStringPrefix::Raw { uppercase_r: false }
1108        } else if self
1109            .0
1110            .contains(InterpolatedStringFlagsInner::R_PREFIX_UPPER)
1111        {
1112            TStringPrefix::Raw { uppercase_r: true }
1113        } else {
1114            TStringPrefix::Regular
1115        }
1116    }
1117}
1118
1119impl StringFlags for FStringFlags {
1120    /// Return `true` if the f-string is triple-quoted, i.e.,
1121    /// it begins and ends with three consecutive quote characters.
1122    /// For example: `f"""{bar}"""`
1123    fn triple_quotes(self) -> TripleQuotes {
1124        if self.0.contains(InterpolatedStringFlagsInner::TRIPLE_QUOTED) {
1125            TripleQuotes::Yes
1126        } else {
1127            TripleQuotes::No
1128        }
1129    }
1130
1131    /// Return the quoting style (single or double quotes)
1132    /// used by the f-string's opener and closer:
1133    /// - `f"{"a"}"` -> `QuoteStyle::Double`
1134    /// - `f'{"a"}'` -> `QuoteStyle::Single`
1135    fn quote_style(self) -> Quote {
1136        if self.0.contains(InterpolatedStringFlagsInner::DOUBLE) {
1137            Quote::Double
1138        } else {
1139            Quote::Single
1140        }
1141    }
1142
1143    fn prefix(self) -> AnyStringPrefix {
1144        AnyStringPrefix::Format(self.prefix())
1145    }
1146
1147    fn is_unclosed(self) -> bool {
1148        self.0.intersects(InterpolatedStringFlagsInner::UNCLOSED)
1149    }
1150}
1151
1152impl fmt::Debug for FStringFlags {
1153    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1154        f.debug_struct("FStringFlags")
1155            .field("quote_style", &self.quote_style())
1156            .field("prefix", &self.prefix())
1157            .field("triple_quoted", &self.is_triple_quoted())
1158            .field("unclosed", &self.is_unclosed())
1159            .finish()
1160    }
1161}
1162
1163impl StringFlags for TStringFlags {
1164    /// Return `true` if the t-string is triple-quoted, i.e.,
1165    /// it begins and ends with three consecutive quote characters.
1166    /// For example: `t"""{bar}"""`
1167    fn triple_quotes(self) -> TripleQuotes {
1168        if self.0.contains(InterpolatedStringFlagsInner::TRIPLE_QUOTED) {
1169            TripleQuotes::Yes
1170        } else {
1171            TripleQuotes::No
1172        }
1173    }
1174
1175    /// Return the quoting style (single or double quotes)
1176    /// used by the t-string's opener and closer:
1177    /// - `t"{"a"}"` -> `QuoteStyle::Double`
1178    /// - `t'{"a"}'` -> `QuoteStyle::Single`
1179    fn quote_style(self) -> Quote {
1180        if self.0.contains(InterpolatedStringFlagsInner::DOUBLE) {
1181            Quote::Double
1182        } else {
1183            Quote::Single
1184        }
1185    }
1186
1187    fn prefix(self) -> AnyStringPrefix {
1188        AnyStringPrefix::Template(self.prefix())
1189    }
1190
1191    fn is_unclosed(self) -> bool {
1192        self.0.intersects(InterpolatedStringFlagsInner::UNCLOSED)
1193    }
1194}
1195
1196impl fmt::Debug for TStringFlags {
1197    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1198        f.debug_struct("TStringFlags")
1199            .field("quote_style", &self.quote_style())
1200            .field("prefix", &self.prefix())
1201            .field("triple_quoted", &self.is_triple_quoted())
1202            .field("unclosed", &self.is_unclosed())
1203            .finish()
1204    }
1205}
1206
1207/// An AST node that represents a single f-string which is part of an [`ExprFString`].
1208#[derive(Clone, Debug, PartialEq)]
1209#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1210pub struct FString {
1211    pub range: TextRange,
1212    pub node_index: AtomicNodeIndex,
1213    pub elements: InterpolatedStringElements,
1214    pub flags: FStringFlags,
1215}
1216
1217impl From<FString> for Expr {
1218    fn from(payload: FString) -> Self {
1219        ExprFString {
1220            node_index: payload.node_index.clone(),
1221            range: payload.range,
1222            value: FStringValue::single(payload),
1223        }
1224        .into()
1225    }
1226}
1227
1228/// A newtype wrapper around a list of [`InterpolatedStringElement`].
1229#[derive(Clone, Default, PartialEq)]
1230#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1231pub struct InterpolatedStringElements(Vec<InterpolatedStringElement>);
1232
1233impl InterpolatedStringElements {
1234    /// Returns an iterator over all the [`InterpolatedStringLiteralElement`] nodes contained in this f-string.
1235    pub fn literals(&self) -> impl Iterator<Item = &InterpolatedStringLiteralElement> {
1236        self.iter().filter_map(|element| element.as_literal())
1237    }
1238
1239    /// Returns an iterator over all the [`InterpolatedElement`] nodes contained in this f-string.
1240    pub fn interpolations(&self) -> impl Iterator<Item = &InterpolatedElement> {
1241        self.iter().filter_map(|element| element.as_interpolation())
1242    }
1243}
1244
1245impl From<Vec<InterpolatedStringElement>> for InterpolatedStringElements {
1246    fn from(elements: Vec<InterpolatedStringElement>) -> Self {
1247        InterpolatedStringElements(elements)
1248    }
1249}
1250
1251impl<'a> IntoIterator for &'a InterpolatedStringElements {
1252    type IntoIter = Iter<'a, InterpolatedStringElement>;
1253    type Item = &'a InterpolatedStringElement;
1254
1255    fn into_iter(self) -> Self::IntoIter {
1256        self.iter()
1257    }
1258}
1259
1260impl<'a> IntoIterator for &'a mut InterpolatedStringElements {
1261    type IntoIter = IterMut<'a, InterpolatedStringElement>;
1262    type Item = &'a mut InterpolatedStringElement;
1263
1264    fn into_iter(self) -> Self::IntoIter {
1265        self.iter_mut()
1266    }
1267}
1268
1269impl Deref for InterpolatedStringElements {
1270    type Target = [InterpolatedStringElement];
1271
1272    fn deref(&self) -> &Self::Target {
1273        &self.0
1274    }
1275}
1276
1277impl DerefMut for InterpolatedStringElements {
1278    fn deref_mut(&mut self) -> &mut Self::Target {
1279        &mut self.0
1280    }
1281}
1282
1283impl fmt::Debug for InterpolatedStringElements {
1284    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1285        fmt::Debug::fmt(&self.0, f)
1286    }
1287}
1288
1289/// An AST node that represents a single t-string which is part of an [`ExprTString`].
1290#[derive(Clone, Debug, PartialEq)]
1291#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1292pub struct TString {
1293    pub range: TextRange,
1294    pub node_index: AtomicNodeIndex,
1295    pub elements: InterpolatedStringElements,
1296    pub flags: TStringFlags,
1297}
1298
1299impl TString {
1300    pub fn quote_style(&self) -> Quote {
1301        self.flags.quote_style()
1302    }
1303
1304    pub fn is_empty(&self) -> bool {
1305        self.elements.is_empty()
1306    }
1307}
1308
1309impl From<TString> for Expr {
1310    fn from(payload: TString) -> Self {
1311        ExprTString {
1312            node_index: payload.node_index.clone(),
1313            range: payload.range,
1314            value: TStringValue::single(payload),
1315        }
1316        .into()
1317    }
1318}
1319
1320impl ExprStringLiteral {
1321    /// Return `Some(literal)` if the string only consists of a single `StringLiteral` part
1322    /// (indicating that it is not implicitly concatenated). Otherwise, return `None`.
1323    pub fn as_single_part_string(&self) -> Option<&StringLiteral> {
1324        match &self.value.inner {
1325            StringLiteralValueInner::Single(value) => Some(value),
1326            StringLiteralValueInner::Concatenated(_) => None,
1327        }
1328    }
1329}
1330
1331impl Ranged for ExprCall {
1332    fn range(&self) -> TextRange {
1333        TextRange::new(self.range_start, self.arguments.end())
1334    }
1335}
1336
1337#[expect(
1338    clippy::missing_fields_in_debug,
1339    reason = "`range_start` is represented by the reconstructed `range` field"
1340)]
1341impl fmt::Debug for ExprCall {
1342    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1343        formatter
1344            .debug_struct("ExprCall")
1345            .field("node_index", &self.node_index)
1346            .field("range", &self.range())
1347            .field("func", &self.func)
1348            .field("arguments", &self.arguments)
1349            .finish()
1350    }
1351}
1352
1353/// The value representing a [`ExprStringLiteral`].
1354#[derive(Clone, Debug, PartialEq)]
1355#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1356pub struct StringLiteralValue {
1357    inner: StringLiteralValueInner,
1358}
1359
1360impl StringLiteralValue {
1361    /// Creates a new string literal with a single [`StringLiteral`] part.
1362    pub fn single(string: StringLiteral) -> Self {
1363        Self {
1364            inner: StringLiteralValueInner::Single(string),
1365        }
1366    }
1367
1368    /// Returns the [`StringLiteralFlags`] associated with this string literal.
1369    ///
1370    /// For an implicitly concatenated string, it returns the flags for the first literal.
1371    pub fn first_literal_flags(&self) -> StringLiteralFlags {
1372        self.iter()
1373            .next()
1374            .expect(
1375                "There should always be at least one string literal in an `ExprStringLiteral` node",
1376            )
1377            .flags
1378    }
1379
1380    /// Creates a new string literal with the given values that represents an
1381    /// implicitly concatenated strings.
1382    ///
1383    /// # Panics
1384    ///
1385    /// Panics if `strings` has less than 2 elements.
1386    /// Use [`StringLiteralValue::single`] instead.
1387    pub fn concatenated(strings: Vec<StringLiteral>) -> Self {
1388        assert!(
1389            strings.len() > 1,
1390            "Use `StringLiteralValue::single` to create single-part strings"
1391        );
1392        Self {
1393            inner: StringLiteralValueInner::Concatenated(Box::new(ConcatenatedStringLiteral {
1394                strings,
1395                value: OnceLock::new(),
1396            })),
1397        }
1398    }
1399
1400    /// Returns `true` if the string literal is implicitly concatenated.
1401    pub const fn is_implicit_concatenated(&self) -> bool {
1402        matches!(self.inner, StringLiteralValueInner::Concatenated(_))
1403    }
1404
1405    /// Returns `true` if the string literal has a `u` prefix, e.g. `u"foo"`.
1406    ///
1407    /// Although all strings in Python 3 are valid unicode (and the `u` prefix
1408    /// is only retained for backwards compatibility), these strings are known as
1409    /// "unicode strings".
1410    ///
1411    /// For an implicitly concatenated string, it returns `true` only if the first
1412    /// [`StringLiteral`] has the `u` prefix.
1413    pub fn is_unicode(&self) -> bool {
1414        self.iter()
1415            .next()
1416            .is_some_and(|part| part.flags.prefix().is_unicode())
1417    }
1418
1419    /// Returns a slice of all the [`StringLiteral`] parts contained in this value.
1420    pub fn as_slice(&self) -> &[StringLiteral] {
1421        match &self.inner {
1422            StringLiteralValueInner::Single(value) => std::slice::from_ref(value),
1423            StringLiteralValueInner::Concatenated(value) => value.strings.as_slice(),
1424        }
1425    }
1426
1427    /// Returns a mutable slice of all the [`StringLiteral`] parts contained in this value.
1428    fn as_mut_slice(&mut self) -> &mut [StringLiteral] {
1429        match &mut self.inner {
1430            StringLiteralValueInner::Single(value) => std::slice::from_mut(value),
1431            StringLiteralValueInner::Concatenated(value) => value.strings.as_mut_slice(),
1432        }
1433    }
1434
1435    /// Returns an iterator over all the [`StringLiteral`] parts contained in this value.
1436    pub fn iter(&self) -> Iter<'_, StringLiteral> {
1437        self.as_slice().iter()
1438    }
1439
1440    /// Returns an iterator over all the [`StringLiteral`] parts contained in this value
1441    /// that allows modification.
1442    pub fn iter_mut(&mut self) -> IterMut<'_, StringLiteral> {
1443        self.as_mut_slice().iter_mut()
1444    }
1445
1446    /// Returns `true` if the node represents an empty string.
1447    ///
1448    /// Note that a [`StringLiteralValue`] node will always have >=1 [`StringLiteral`] parts
1449    /// inside it. This method checks whether the value of the concatenated parts is equal
1450    /// to the empty string, not whether the string has 0 parts inside it.
1451    pub fn is_empty(&self) -> bool {
1452        self.len() == 0
1453    }
1454
1455    /// Returns the total length of the string literal value, in bytes, not
1456    /// [`char`]s or graphemes.
1457    pub fn len(&self) -> usize {
1458        self.iter().fold(0, |acc, part| acc + part.value.len())
1459    }
1460
1461    /// Returns an iterator over the [`char`]s of each string literal part.
1462    pub fn chars(&self) -> impl Iterator<Item = char> + Clone + '_ {
1463        self.iter().flat_map(|part| part.value.chars())
1464    }
1465
1466    /// Returns the concatenated string value as a [`str`].
1467    ///
1468    /// Note that this will perform an allocation on the first invocation if the
1469    /// string value is implicitly concatenated.
1470    pub fn to_str(&self) -> &str {
1471        match &self.inner {
1472            StringLiteralValueInner::Single(value) => value.as_str(),
1473            StringLiteralValueInner::Concatenated(value) => value.to_str(),
1474        }
1475    }
1476}
1477
1478impl<'a> IntoIterator for &'a StringLiteralValue {
1479    type Item = &'a StringLiteral;
1480    type IntoIter = Iter<'a, StringLiteral>;
1481
1482    fn into_iter(self) -> Self::IntoIter {
1483        self.iter()
1484    }
1485}
1486
1487impl<'a> IntoIterator for &'a mut StringLiteralValue {
1488    type Item = &'a mut StringLiteral;
1489    type IntoIter = IterMut<'a, StringLiteral>;
1490    fn into_iter(self) -> Self::IntoIter {
1491        self.iter_mut()
1492    }
1493}
1494
1495impl PartialEq<str> for StringLiteralValue {
1496    fn eq(&self, other: &str) -> bool {
1497        if self.len() != other.len() {
1498            return false;
1499        }
1500        // The `zip` here is safe because we have checked the length of both parts.
1501        self.chars().zip(other.chars()).all(|(c1, c2)| c1 == c2)
1502    }
1503}
1504
1505impl fmt::Display for StringLiteralValue {
1506    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1507        f.write_str(self.to_str())
1508    }
1509}
1510
1511/// An internal representation of [`StringLiteralValue`].
1512#[derive(Clone, Debug, PartialEq)]
1513#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1514enum StringLiteralValueInner {
1515    /// A single string literal i.e., `"foo"`.
1516    Single(StringLiteral),
1517
1518    /// An implicitly concatenated string literals i.e., `"foo" "bar"`.
1519    Concatenated(Box<ConcatenatedStringLiteral>),
1520}
1521
1522bitflags! {
1523    #[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
1524    struct StringLiteralFlagsInner: u8 {
1525        /// The string uses double quotes (e.g. `"foo"`).
1526        /// If this flag is not set, the string uses single quotes (`'foo'`).
1527        const DOUBLE = 1 << 0;
1528
1529        /// The string is triple-quoted (`"""foo"""`):
1530        /// it begins and ends with three consecutive quote characters.
1531        const TRIPLE_QUOTED = 1 << 1;
1532
1533        /// The string has a `u` or `U` prefix, e.g. `u"foo"`.
1534        /// While this prefix is a no-op at runtime,
1535        /// strings with this prefix can have no other prefixes set;
1536        /// it is therefore invalid for this flag to be set
1537        /// if `R_PREFIX` is also set.
1538        const U_PREFIX = 1 << 2;
1539
1540        /// The string has an `r` prefix, meaning it is a raw string
1541        /// with a lowercase 'r' (e.g. `r"foo\."`).
1542        /// It is invalid to set this flag if `U_PREFIX` is also set.
1543        const R_PREFIX_LOWER = 1 << 3;
1544
1545        /// The string has an `R` prefix, meaning it is a raw string
1546        /// with an uppercase 'R' (e.g. `R'foo\d'`).
1547        /// See https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#r-strings-and-r-strings
1548        /// for why we track the casing of the `r` prefix,
1549        /// but not for any other prefix
1550        const R_PREFIX_UPPER = 1 << 4;
1551
1552        /// The string was deemed invalid by the parser.
1553        const INVALID = 1 << 5;
1554
1555        /// The string literal misses the matching closing quote(s).
1556        const UNCLOSED = 1 << 6;
1557    }
1558}
1559
1560#[cfg(feature = "get-size")]
1561impl get_size2::GetSize for StringLiteralFlagsInner {}
1562
1563/// Flags that can be queried to obtain information
1564/// regarding the prefixes and quotes used for a string literal.
1565///
1566/// ## Notes on usage
1567///
1568/// If you're using a `Generator` from the `ruff_python_codegen` crate to generate a lint-rule fix
1569/// from an existing string literal, consider passing along the [`StringLiteral::flags`] field or
1570/// the result of the [`StringLiteralValue::first_literal_flags`] method. If you don't have an
1571/// existing string but have a `Checker` from the `ruff_linter` crate available, consider using
1572/// `Checker::default_string_flags` to create instances of this struct; this method will properly
1573/// handle surrounding f-strings. For usage that doesn't fit into one of these categories, the
1574/// public constructor [`StringLiteralFlags::empty`] can be used.
1575#[derive(Copy, Clone, Eq, PartialEq, Hash)]
1576#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1577pub struct StringLiteralFlags(StringLiteralFlagsInner);
1578
1579impl StringLiteralFlags {
1580    /// Construct a new [`StringLiteralFlags`] with **no flags set**.
1581    ///
1582    /// See [`StringLiteralFlags::with_quote_style`], [`StringLiteralFlags::with_triple_quotes`],
1583    /// and [`StringLiteralFlags::with_prefix`] for ways of setting the quote style (single or
1584    /// double), enabling triple quotes, and adding prefixes (such as `r` or `u`), respectively.
1585    ///
1586    /// See the documentation for [`StringLiteralFlags`] for additional caveats on this constructor,
1587    /// and situations in which alternative ways to construct this struct should be used, especially
1588    /// when writing lint rules.
1589    pub fn empty() -> Self {
1590        Self(StringLiteralFlagsInner::empty())
1591    }
1592
1593    #[must_use]
1594    pub fn with_quote_style(mut self, quote_style: Quote) -> Self {
1595        self.0
1596            .set(StringLiteralFlagsInner::DOUBLE, quote_style.is_double());
1597        self
1598    }
1599
1600    #[must_use]
1601    pub fn with_triple_quotes(mut self, triple_quotes: TripleQuotes) -> Self {
1602        self.0.set(
1603            StringLiteralFlagsInner::TRIPLE_QUOTED,
1604            triple_quotes.is_yes(),
1605        );
1606        self
1607    }
1608
1609    #[must_use]
1610    pub fn with_unclosed(mut self, unclosed: bool) -> Self {
1611        self.0.set(StringLiteralFlagsInner::UNCLOSED, unclosed);
1612        self
1613    }
1614
1615    #[must_use]
1616    pub fn with_prefix(self, prefix: StringLiteralPrefix) -> Self {
1617        let StringLiteralFlags(flags) = self;
1618        match prefix {
1619            StringLiteralPrefix::Empty => Self(
1620                flags
1621                    - StringLiteralFlagsInner::R_PREFIX_LOWER
1622                    - StringLiteralFlagsInner::R_PREFIX_UPPER
1623                    - StringLiteralFlagsInner::U_PREFIX,
1624            ),
1625            StringLiteralPrefix::Raw { uppercase: false } => Self(
1626                (flags | StringLiteralFlagsInner::R_PREFIX_LOWER)
1627                    - StringLiteralFlagsInner::R_PREFIX_UPPER
1628                    - StringLiteralFlagsInner::U_PREFIX,
1629            ),
1630            StringLiteralPrefix::Raw { uppercase: true } => Self(
1631                (flags | StringLiteralFlagsInner::R_PREFIX_UPPER)
1632                    - StringLiteralFlagsInner::R_PREFIX_LOWER
1633                    - StringLiteralFlagsInner::U_PREFIX,
1634            ),
1635            StringLiteralPrefix::Unicode => Self(
1636                (flags | StringLiteralFlagsInner::U_PREFIX)
1637                    - StringLiteralFlagsInner::R_PREFIX_LOWER
1638                    - StringLiteralFlagsInner::R_PREFIX_UPPER,
1639            ),
1640        }
1641    }
1642
1643    #[must_use]
1644    pub fn with_invalid(mut self) -> Self {
1645        self.0 |= StringLiteralFlagsInner::INVALID;
1646        self
1647    }
1648
1649    /// Returns `true` if the parser deemed the string literal invalid.
1650    pub const fn is_invalid(self) -> bool {
1651        self.0.contains(StringLiteralFlagsInner::INVALID)
1652    }
1653
1654    pub const fn prefix(self) -> StringLiteralPrefix {
1655        if self.0.contains(StringLiteralFlagsInner::U_PREFIX) {
1656            debug_assert!(
1657                !self.0.intersects(
1658                    StringLiteralFlagsInner::R_PREFIX_LOWER
1659                        .union(StringLiteralFlagsInner::R_PREFIX_UPPER)
1660                )
1661            );
1662            StringLiteralPrefix::Unicode
1663        } else if self.0.contains(StringLiteralFlagsInner::R_PREFIX_LOWER) {
1664            debug_assert!(!self.0.contains(StringLiteralFlagsInner::R_PREFIX_UPPER));
1665            StringLiteralPrefix::Raw { uppercase: false }
1666        } else if self.0.contains(StringLiteralFlagsInner::R_PREFIX_UPPER) {
1667            StringLiteralPrefix::Raw { uppercase: true }
1668        } else {
1669            StringLiteralPrefix::Empty
1670        }
1671    }
1672}
1673
1674impl StringFlags for StringLiteralFlags {
1675    /// Return the quoting style (single or double quotes)
1676    /// used by the string's opener and closer:
1677    /// - `"a"` -> `QuoteStyle::Double`
1678    /// - `'a'` -> `QuoteStyle::Single`
1679    fn quote_style(self) -> Quote {
1680        if self.0.contains(StringLiteralFlagsInner::DOUBLE) {
1681            Quote::Double
1682        } else {
1683            Quote::Single
1684        }
1685    }
1686
1687    /// Return `true` if the string is triple-quoted, i.e.,
1688    /// it begins and ends with three consecutive quote characters.
1689    /// For example: `"""bar"""`
1690    fn triple_quotes(self) -> TripleQuotes {
1691        if self.0.contains(StringLiteralFlagsInner::TRIPLE_QUOTED) {
1692            TripleQuotes::Yes
1693        } else {
1694            TripleQuotes::No
1695        }
1696    }
1697
1698    fn prefix(self) -> AnyStringPrefix {
1699        AnyStringPrefix::Regular(self.prefix())
1700    }
1701
1702    fn is_unclosed(self) -> bool {
1703        self.0.intersects(StringLiteralFlagsInner::UNCLOSED)
1704    }
1705}
1706
1707impl fmt::Debug for StringLiteralFlags {
1708    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1709        f.debug_struct("StringLiteralFlags")
1710            .field("quote_style", &self.quote_style())
1711            .field("prefix", &self.prefix())
1712            .field("triple_quoted", &self.is_triple_quoted())
1713            .field("unclosed", &self.is_unclosed())
1714            .finish()
1715    }
1716}
1717
1718/// An AST node that represents a single string literal which is part of an
1719/// [`ExprStringLiteral`].
1720#[derive(Clone, Debug, PartialEq)]
1721#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1722pub struct StringLiteral {
1723    pub range: TextRange,
1724    pub node_index: AtomicNodeIndex,
1725    pub value: Box<str>,
1726    pub flags: StringLiteralFlags,
1727}
1728
1729impl Deref for StringLiteral {
1730    type Target = str;
1731
1732    fn deref(&self) -> &Self::Target {
1733        &self.value
1734    }
1735}
1736
1737impl StringLiteral {
1738    /// Extracts a string slice containing the entire `String`.
1739    pub fn as_str(&self) -> &str {
1740        self
1741    }
1742
1743    /// Creates an invalid string literal with the given range.
1744    pub fn invalid(range: TextRange) -> Self {
1745        Self {
1746            range,
1747            value: "".into(),
1748            node_index: AtomicNodeIndex::NONE,
1749            flags: StringLiteralFlags::empty().with_invalid(),
1750        }
1751    }
1752
1753    /// The range of the string literal's contents.
1754    ///
1755    /// This excludes any prefixes, opening quotes or closing quotes.
1756    pub fn content_range(&self) -> TextRange {
1757        TextRange::new(
1758            self.start() + self.flags.opener_len(),
1759            self.end() - self.flags.closer_len(),
1760        )
1761    }
1762}
1763
1764impl From<StringLiteral> for Expr {
1765    fn from(payload: StringLiteral) -> Self {
1766        ExprStringLiteral {
1767            range: payload.range,
1768            node_index: AtomicNodeIndex::NONE,
1769            value: StringLiteralValue::single(payload),
1770        }
1771        .into()
1772    }
1773}
1774
1775/// An internal representation of [`StringLiteral`] that represents an
1776/// implicitly concatenated string.
1777#[derive(Clone)]
1778#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1779struct ConcatenatedStringLiteral {
1780    /// The individual [`StringLiteral`] parts that make up the concatenated string.
1781    strings: Vec<StringLiteral>,
1782    /// The concatenated string value.
1783    value: OnceLock<Box<str>>,
1784}
1785
1786impl ConcatenatedStringLiteral {
1787    /// Extracts a string slice containing the entire concatenated string.
1788    fn to_str(&self) -> &str {
1789        self.value.get_or_init(|| {
1790            let concatenated: String = self.strings.iter().map(StringLiteral::as_str).collect();
1791            concatenated.into_boxed_str()
1792        })
1793    }
1794}
1795
1796impl PartialEq for ConcatenatedStringLiteral {
1797    fn eq(&self, other: &Self) -> bool {
1798        if self.strings.len() != other.strings.len() {
1799            return false;
1800        }
1801        // The `zip` here is safe because we have checked the length of both parts.
1802        self.strings
1803            .iter()
1804            .zip(&other.strings)
1805            .all(|(s1, s2)| s1 == s2)
1806    }
1807}
1808
1809impl Debug for ConcatenatedStringLiteral {
1810    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1811        f.debug_struct("ConcatenatedStringLiteral")
1812            .field("strings", &self.strings)
1813            .field("value", &self.to_str())
1814            .finish()
1815    }
1816}
1817
1818impl ExprBytesLiteral {
1819    /// Return `Some(literal)` if the bytestring only consists of a single `BytesLiteral` part
1820    /// (indicating that it is not implicitly concatenated). Otherwise, return `None`.
1821    pub const fn as_single_part_bytestring(&self) -> Option<&BytesLiteral> {
1822        match &self.value.inner {
1823            BytesLiteralValueInner::Single(value) => Some(value),
1824            BytesLiteralValueInner::Concatenated(_) => None,
1825        }
1826    }
1827}
1828
1829/// The value representing a [`ExprBytesLiteral`].
1830#[derive(Clone, Debug, PartialEq)]
1831#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1832pub struct BytesLiteralValue {
1833    inner: BytesLiteralValueInner,
1834}
1835
1836impl BytesLiteralValue {
1837    /// Create a new bytestring literal with a single [`BytesLiteral`] part.
1838    pub fn single(value: BytesLiteral) -> Self {
1839        Self {
1840            inner: BytesLiteralValueInner::Single(value),
1841        }
1842    }
1843
1844    /// Creates a new bytestring literal with the given values that represents an
1845    /// implicitly concatenated bytestring.
1846    ///
1847    /// # Panics
1848    ///
1849    /// Panics if `values` has less than 2 elements.
1850    /// Use [`BytesLiteralValue::single`] instead.
1851    pub fn concatenated(values: Vec<BytesLiteral>) -> Self {
1852        assert!(
1853            values.len() > 1,
1854            "Use `BytesLiteralValue::single` to create single-part bytestrings"
1855        );
1856        Self {
1857            inner: BytesLiteralValueInner::Concatenated(values),
1858        }
1859    }
1860
1861    /// Returns `true` if the bytestring is implicitly concatenated.
1862    pub const fn is_implicit_concatenated(&self) -> bool {
1863        matches!(self.inner, BytesLiteralValueInner::Concatenated(_))
1864    }
1865
1866    /// Returns a slice of all the [`BytesLiteral`] parts contained in this value.
1867    pub fn as_slice(&self) -> &[BytesLiteral] {
1868        match &self.inner {
1869            BytesLiteralValueInner::Single(value) => std::slice::from_ref(value),
1870            BytesLiteralValueInner::Concatenated(value) => value.as_slice(),
1871        }
1872    }
1873
1874    /// Returns a mutable slice of all the [`BytesLiteral`] parts contained in this value.
1875    fn as_mut_slice(&mut self) -> &mut [BytesLiteral] {
1876        match &mut self.inner {
1877            BytesLiteralValueInner::Single(value) => std::slice::from_mut(value),
1878            BytesLiteralValueInner::Concatenated(value) => value.as_mut_slice(),
1879        }
1880    }
1881
1882    /// Returns an iterator over all the [`BytesLiteral`] parts contained in this value.
1883    pub fn iter(&self) -> Iter<'_, BytesLiteral> {
1884        self.as_slice().iter()
1885    }
1886
1887    /// Returns an iterator over all the [`BytesLiteral`] parts contained in this value
1888    /// that allows modification.
1889    pub fn iter_mut(&mut self) -> IterMut<'_, BytesLiteral> {
1890        self.as_mut_slice().iter_mut()
1891    }
1892
1893    /// Return `true` if the node represents an empty bytestring.
1894    ///
1895    /// Note that a [`BytesLiteralValue`] node will always have >=1 [`BytesLiteral`] parts
1896    /// inside it. This method checks whether the value of the concatenated parts is equal
1897    /// to the empty bytestring, not whether the bytestring has 0 parts inside it.
1898    pub fn is_empty(&self) -> bool {
1899        self.iter().all(|part| part.is_empty())
1900    }
1901
1902    /// Returns the length of the concatenated bytestring.
1903    pub fn len(&self) -> usize {
1904        self.iter().map(|part| part.len()).sum()
1905    }
1906
1907    /// Returns an iterator over the bytes of the concatenated bytestring.
1908    pub fn bytes(&self) -> impl Iterator<Item = u8> + '_ {
1909        self.iter().flat_map(|part| part.as_slice().iter().copied())
1910    }
1911}
1912
1913impl<'a> IntoIterator for &'a BytesLiteralValue {
1914    type Item = &'a BytesLiteral;
1915    type IntoIter = Iter<'a, BytesLiteral>;
1916
1917    fn into_iter(self) -> Self::IntoIter {
1918        self.iter()
1919    }
1920}
1921
1922impl<'a> IntoIterator for &'a mut BytesLiteralValue {
1923    type Item = &'a mut BytesLiteral;
1924    type IntoIter = IterMut<'a, BytesLiteral>;
1925    fn into_iter(self) -> Self::IntoIter {
1926        self.iter_mut()
1927    }
1928}
1929
1930impl PartialEq<[u8]> for BytesLiteralValue {
1931    fn eq(&self, other: &[u8]) -> bool {
1932        if self.len() != other.len() {
1933            return false;
1934        }
1935        // The `zip` here is safe because we have checked the length of both parts.
1936        self.bytes()
1937            .zip(other.iter().copied())
1938            .all(|(b1, b2)| b1 == b2)
1939    }
1940}
1941
1942impl<'a> From<&'a BytesLiteralValue> for Cow<'a, [u8]> {
1943    fn from(value: &'a BytesLiteralValue) -> Self {
1944        match &value.inner {
1945            BytesLiteralValueInner::Single(BytesLiteral {
1946                value: bytes_value, ..
1947            }) => Cow::from(bytes_value.as_ref()),
1948            BytesLiteralValueInner::Concatenated(bytes_literal_vec) => Cow::Owned(
1949                bytes_literal_vec
1950                    .iter()
1951                    .flat_map(|bytes_literal| bytes_literal.value.to_vec())
1952                    .collect::<Vec<u8>>(),
1953            ),
1954        }
1955    }
1956}
1957
1958/// An internal representation of [`BytesLiteralValue`].
1959#[derive(Clone, Debug, PartialEq)]
1960#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1961enum BytesLiteralValueInner {
1962    /// A single-part bytestring literal i.e., `b"foo"`.
1963    Single(BytesLiteral),
1964
1965    /// An implicitly concatenated bytestring literal i.e., `b"foo" b"bar"`.
1966    Concatenated(Vec<BytesLiteral>),
1967}
1968
1969bitflags! {
1970    #[derive(Default, Copy, Clone, PartialEq, Eq, Hash)]
1971    struct BytesLiteralFlagsInner: u8 {
1972        /// The bytestring uses double quotes (e.g. `b"foo"`).
1973        /// If this flag is not set, the bytestring uses single quotes (e.g. `b'foo'`).
1974        const DOUBLE = 1 << 0;
1975
1976        /// The bytestring is triple-quoted (e.g. `b"""foo"""`):
1977        /// it begins and ends with three consecutive quote characters.
1978        const TRIPLE_QUOTED = 1 << 1;
1979
1980        /// The bytestring has an `r` prefix (e.g. `rb"foo"`),
1981        /// meaning it is a raw bytestring with a lowercase 'r'.
1982        const R_PREFIX_LOWER = 1 << 2;
1983
1984        /// The bytestring has an `R` prefix (e.g. `Rb"foo"`),
1985        /// meaning it is a raw bytestring with an uppercase 'R'.
1986        /// See https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#r-strings-and-r-strings
1987        /// for why we track the casing of the `r` prefix, but not for any other prefix
1988        const R_PREFIX_UPPER = 1 << 3;
1989
1990        /// The bytestring was deemed invalid by the parser.
1991        const INVALID = 1 << 4;
1992
1993        /// The byte string misses the matching closing quote(s).
1994        const UNCLOSED = 1 << 5;
1995    }
1996}
1997
1998#[cfg(feature = "get-size")]
1999impl get_size2::GetSize for BytesLiteralFlagsInner {}
2000
2001/// Flags that can be queried to obtain information
2002/// regarding the prefixes and quotes used for a bytes literal.
2003///
2004/// ## Notes on usage
2005///
2006/// If you're using a `Generator` from the `ruff_python_codegen` crate to generate a lint-rule fix
2007/// from an existing bytes literal, consider passing along the [`BytesLiteral::flags`] field. If
2008/// you don't have an existing literal but have a `Checker` from the `ruff_linter` crate available,
2009/// consider using `Checker::default_bytes_flags` to create instances of this struct; this method
2010/// will properly handle surrounding f-strings. For usage that doesn't fit into one of these
2011/// categories, the public constructor [`BytesLiteralFlags::empty`] can be used.
2012#[derive(Copy, Clone, Eq, PartialEq, Hash)]
2013#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2014pub struct BytesLiteralFlags(BytesLiteralFlagsInner);
2015
2016impl BytesLiteralFlags {
2017    /// Construct a new [`BytesLiteralFlags`] with **no flags set**.
2018    ///
2019    /// See [`BytesLiteralFlags::with_quote_style`], [`BytesLiteralFlags::with_triple_quotes`], and
2020    /// [`BytesLiteralFlags::with_prefix`] for ways of setting the quote style (single or double),
2021    /// enabling triple quotes, and adding prefixes (such as `r`), respectively.
2022    ///
2023    /// See the documentation for [`BytesLiteralFlags`] for additional caveats on this constructor,
2024    /// and situations in which alternative ways to construct this struct should be used, especially
2025    /// when writing lint rules.
2026    pub fn empty() -> Self {
2027        Self(BytesLiteralFlagsInner::empty())
2028    }
2029
2030    #[must_use]
2031    pub fn with_quote_style(mut self, quote_style: Quote) -> Self {
2032        self.0
2033            .set(BytesLiteralFlagsInner::DOUBLE, quote_style.is_double());
2034        self
2035    }
2036
2037    #[must_use]
2038    pub fn with_triple_quotes(mut self, triple_quotes: TripleQuotes) -> Self {
2039        self.0.set(
2040            BytesLiteralFlagsInner::TRIPLE_QUOTED,
2041            triple_quotes.is_yes(),
2042        );
2043        self
2044    }
2045
2046    #[must_use]
2047    pub fn with_unclosed(mut self, unclosed: bool) -> Self {
2048        self.0.set(BytesLiteralFlagsInner::UNCLOSED, unclosed);
2049        self
2050    }
2051
2052    #[must_use]
2053    pub fn with_prefix(mut self, prefix: ByteStringPrefix) -> Self {
2054        match prefix {
2055            ByteStringPrefix::Regular => {
2056                self.0 -= BytesLiteralFlagsInner::R_PREFIX_LOWER;
2057                self.0 -= BytesLiteralFlagsInner::R_PREFIX_UPPER;
2058            }
2059            ByteStringPrefix::Raw { uppercase_r } => {
2060                self.0
2061                    .set(BytesLiteralFlagsInner::R_PREFIX_UPPER, uppercase_r);
2062                self.0
2063                    .set(BytesLiteralFlagsInner::R_PREFIX_LOWER, !uppercase_r);
2064            }
2065        }
2066        self
2067    }
2068
2069    #[must_use]
2070    pub fn with_invalid(mut self) -> Self {
2071        self.0 |= BytesLiteralFlagsInner::INVALID;
2072        self
2073    }
2074
2075    /// Returns `true` if the parser deemed the bytes literal invalid.
2076    pub const fn is_invalid(self) -> bool {
2077        self.0.contains(BytesLiteralFlagsInner::INVALID)
2078    }
2079
2080    pub const fn prefix(self) -> ByteStringPrefix {
2081        if self.0.contains(BytesLiteralFlagsInner::R_PREFIX_LOWER) {
2082            debug_assert!(!self.0.contains(BytesLiteralFlagsInner::R_PREFIX_UPPER));
2083            ByteStringPrefix::Raw { uppercase_r: false }
2084        } else if self.0.contains(BytesLiteralFlagsInner::R_PREFIX_UPPER) {
2085            ByteStringPrefix::Raw { uppercase_r: true }
2086        } else {
2087            ByteStringPrefix::Regular
2088        }
2089    }
2090}
2091
2092impl StringFlags for BytesLiteralFlags {
2093    /// Return `true` if the bytestring is triple-quoted, i.e.,
2094    /// it begins and ends with three consecutive quote characters.
2095    /// For example: `b"""{bar}"""`
2096    fn triple_quotes(self) -> TripleQuotes {
2097        if self.0.contains(BytesLiteralFlagsInner::TRIPLE_QUOTED) {
2098            TripleQuotes::Yes
2099        } else {
2100            TripleQuotes::No
2101        }
2102    }
2103
2104    /// Return the quoting style (single or double quotes)
2105    /// used by the bytestring's opener and closer:
2106    /// - `b"a"` -> `QuoteStyle::Double`
2107    /// - `b'a'` -> `QuoteStyle::Single`
2108    fn quote_style(self) -> Quote {
2109        if self.0.contains(BytesLiteralFlagsInner::DOUBLE) {
2110            Quote::Double
2111        } else {
2112            Quote::Single
2113        }
2114    }
2115
2116    fn prefix(self) -> AnyStringPrefix {
2117        AnyStringPrefix::Bytes(self.prefix())
2118    }
2119
2120    fn is_unclosed(self) -> bool {
2121        self.0.intersects(BytesLiteralFlagsInner::UNCLOSED)
2122    }
2123}
2124
2125impl fmt::Debug for BytesLiteralFlags {
2126    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2127        f.debug_struct("BytesLiteralFlags")
2128            .field("quote_style", &self.quote_style())
2129            .field("prefix", &self.prefix())
2130            .field("triple_quoted", &self.is_triple_quoted())
2131            .field("unclosed", &self.is_unclosed())
2132            .finish()
2133    }
2134}
2135
2136/// An AST node that represents a single bytes literal which is part of an
2137/// [`ExprBytesLiteral`].
2138#[derive(Clone, Debug, PartialEq)]
2139#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2140pub struct BytesLiteral {
2141    pub range: TextRange,
2142    pub node_index: AtomicNodeIndex,
2143    pub value: Box<[u8]>,
2144    pub flags: BytesLiteralFlags,
2145}
2146
2147impl Deref for BytesLiteral {
2148    type Target = [u8];
2149
2150    fn deref(&self) -> &Self::Target {
2151        &self.value
2152    }
2153}
2154
2155impl BytesLiteral {
2156    /// Extracts a byte slice containing the entire [`BytesLiteral`].
2157    pub fn as_slice(&self) -> &[u8] {
2158        self
2159    }
2160
2161    /// Creates a new invalid bytes literal with the given range.
2162    pub fn invalid(range: TextRange) -> Self {
2163        Self {
2164            range,
2165            value: Box::new([]),
2166            node_index: AtomicNodeIndex::NONE,
2167            flags: BytesLiteralFlags::empty().with_invalid(),
2168        }
2169    }
2170
2171    /// The range of the byte literal's contents.
2172    ///
2173    /// This excludes any prefixes, opening quotes or closing quotes.
2174    pub fn content_range(&self) -> TextRange {
2175        TextRange::new(
2176            self.start() + self.flags.opener_len(),
2177            self.end() - self.flags.closer_len(),
2178        )
2179    }
2180}
2181
2182impl From<BytesLiteral> for Expr {
2183    fn from(payload: BytesLiteral) -> Self {
2184        ExprBytesLiteral {
2185            range: payload.range,
2186            node_index: AtomicNodeIndex::NONE,
2187            value: BytesLiteralValue::single(payload),
2188        }
2189        .into()
2190    }
2191}
2192
2193bitflags! {
2194    /// Flags that can be queried to obtain information
2195    /// regarding the prefixes and quotes used for a string literal.
2196    ///
2197    /// Note that not all of these flags can be validly combined -- e.g.,
2198    /// it is invalid to combine the `U_PREFIX` flag with any other
2199    /// of the `*_PREFIX` flags. As such, the recommended way to set the
2200    /// prefix flags is by calling the `as_flags()` method on the
2201    /// `StringPrefix` enum.
2202    #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
2203    struct AnyStringFlagsInner: u16 {
2204        /// The string uses double quotes (`"`).
2205        /// If this flag is not set, the string uses single quotes (`'`).
2206        const DOUBLE = 1 << 0;
2207
2208        /// The string is triple-quoted:
2209        /// it begins and ends with three consecutive quote characters.
2210        const TRIPLE_QUOTED = 1 << 1;
2211
2212        /// The string has a `u` or `U` prefix.
2213        /// While this prefix is a no-op at runtime,
2214        /// strings with this prefix can have no other prefixes set.
2215        const U_PREFIX = 1 << 2;
2216
2217        /// The string has a `b` or `B` prefix.
2218        /// This means that the string is a sequence of `int`s at runtime,
2219        /// rather than a sequence of `str`s.
2220        /// Strings with this flag can also be raw strings,
2221        /// but can have no other prefixes.
2222        const B_PREFIX = 1 << 3;
2223
2224        /// The string has a `f` or `F` prefix, meaning it is an f-string.
2225        /// F-strings can also be raw strings,
2226        /// but can have no other prefixes.
2227        const F_PREFIX = 1 << 4;
2228
2229        /// The string has a `t` or `T` prefix, meaning it is a t-string.
2230        /// T-strings can also be raw strings,
2231        /// but can have no other prefixes.
2232        const T_PREFIX = 1 << 5;
2233
2234        /// The string has an `r` prefix, meaning it is a raw string.
2235        /// F-strings and byte-strings can be raw,
2236        /// as can strings with no other prefixes.
2237        /// U-strings cannot be raw.
2238        const R_PREFIX_LOWER = 1 << 6;
2239
2240        /// The string has an `R` prefix, meaning it is a raw string.
2241        /// The casing of the `r`/`R` has no semantic significance at runtime;
2242        /// see https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#r-strings-and-r-strings
2243        /// for why we track the casing of the `r` prefix,
2244        /// but not for any other prefix
2245        const R_PREFIX_UPPER = 1 << 7;
2246
2247        /// String without matching closing quote(s).
2248        const UNCLOSED = 1 << 8;
2249    }
2250}
2251
2252#[derive(Clone, Copy, PartialEq, Eq, Hash)]
2253pub struct AnyStringFlags(AnyStringFlagsInner);
2254
2255impl AnyStringFlags {
2256    #[must_use]
2257    pub fn with_prefix(mut self, prefix: AnyStringPrefix) -> Self {
2258        self.0 |= match prefix {
2259            // regular strings
2260            AnyStringPrefix::Regular(StringLiteralPrefix::Empty) => AnyStringFlagsInner::empty(),
2261            AnyStringPrefix::Regular(StringLiteralPrefix::Unicode) => AnyStringFlagsInner::U_PREFIX,
2262            AnyStringPrefix::Regular(StringLiteralPrefix::Raw { uppercase: false }) => {
2263                AnyStringFlagsInner::R_PREFIX_LOWER
2264            }
2265            AnyStringPrefix::Regular(StringLiteralPrefix::Raw { uppercase: true }) => {
2266                AnyStringFlagsInner::R_PREFIX_UPPER
2267            }
2268
2269            // bytestrings
2270            AnyStringPrefix::Bytes(ByteStringPrefix::Regular) => AnyStringFlagsInner::B_PREFIX,
2271            AnyStringPrefix::Bytes(ByteStringPrefix::Raw { uppercase_r: false }) => {
2272                AnyStringFlagsInner::B_PREFIX.union(AnyStringFlagsInner::R_PREFIX_LOWER)
2273            }
2274            AnyStringPrefix::Bytes(ByteStringPrefix::Raw { uppercase_r: true }) => {
2275                AnyStringFlagsInner::B_PREFIX.union(AnyStringFlagsInner::R_PREFIX_UPPER)
2276            }
2277
2278            // f-strings
2279            AnyStringPrefix::Format(FStringPrefix::Regular) => AnyStringFlagsInner::F_PREFIX,
2280            AnyStringPrefix::Format(FStringPrefix::Raw { uppercase_r: false }) => {
2281                AnyStringFlagsInner::F_PREFIX.union(AnyStringFlagsInner::R_PREFIX_LOWER)
2282            }
2283            AnyStringPrefix::Format(FStringPrefix::Raw { uppercase_r: true }) => {
2284                AnyStringFlagsInner::F_PREFIX.union(AnyStringFlagsInner::R_PREFIX_UPPER)
2285            }
2286
2287            // t-strings
2288            AnyStringPrefix::Template(TStringPrefix::Regular) => AnyStringFlagsInner::T_PREFIX,
2289            AnyStringPrefix::Template(TStringPrefix::Raw { uppercase_r: false }) => {
2290                AnyStringFlagsInner::T_PREFIX.union(AnyStringFlagsInner::R_PREFIX_LOWER)
2291            }
2292            AnyStringPrefix::Template(TStringPrefix::Raw { uppercase_r: true }) => {
2293                AnyStringFlagsInner::T_PREFIX.union(AnyStringFlagsInner::R_PREFIX_UPPER)
2294            }
2295        };
2296        self
2297    }
2298
2299    pub fn new(prefix: AnyStringPrefix, quotes: Quote, triple_quotes: TripleQuotes) -> Self {
2300        Self(AnyStringFlagsInner::empty())
2301            .with_prefix(prefix)
2302            .with_quote_style(quotes)
2303            .with_triple_quotes(triple_quotes)
2304    }
2305
2306    /// Does the string have a `u` or `U` prefix?
2307    pub const fn is_u_string(self) -> bool {
2308        self.0.contains(AnyStringFlagsInner::U_PREFIX)
2309    }
2310
2311    /// Does the string have an `r` or `R` prefix?
2312    pub const fn is_raw_string(self) -> bool {
2313        self.0.intersects(
2314            AnyStringFlagsInner::R_PREFIX_LOWER.union(AnyStringFlagsInner::R_PREFIX_UPPER),
2315        )
2316    }
2317
2318    /// Does the string have an `f`,`F`,`t`, or `T` prefix?
2319    pub const fn is_interpolated_string(self) -> bool {
2320        self.0
2321            .intersects(AnyStringFlagsInner::F_PREFIX.union(AnyStringFlagsInner::T_PREFIX))
2322    }
2323
2324    /// Does the string have a `b` or `B` prefix?
2325    pub const fn is_byte_string(self) -> bool {
2326        self.0.contains(AnyStringFlagsInner::B_PREFIX)
2327    }
2328
2329    #[must_use]
2330    pub fn with_quote_style(mut self, quotes: Quote) -> Self {
2331        match quotes {
2332            Quote::Double => self.0 |= AnyStringFlagsInner::DOUBLE,
2333            Quote::Single => self.0 -= AnyStringFlagsInner::DOUBLE,
2334        }
2335        self
2336    }
2337
2338    #[must_use]
2339    pub fn with_triple_quotes(mut self, triple_quotes: TripleQuotes) -> Self {
2340        self.0
2341            .set(AnyStringFlagsInner::TRIPLE_QUOTED, triple_quotes.is_yes());
2342        self
2343    }
2344
2345    #[must_use]
2346    pub fn with_unclosed(mut self, unclosed: bool) -> Self {
2347        self.0.set(AnyStringFlagsInner::UNCLOSED, unclosed);
2348        self
2349    }
2350}
2351
2352impl StringFlags for AnyStringFlags {
2353    /// Does the string use single or double quotes in its opener and closer?
2354    fn quote_style(self) -> Quote {
2355        if self.0.contains(AnyStringFlagsInner::DOUBLE) {
2356            Quote::Double
2357        } else {
2358            Quote::Single
2359        }
2360    }
2361
2362    fn triple_quotes(self) -> TripleQuotes {
2363        if self.0.contains(AnyStringFlagsInner::TRIPLE_QUOTED) {
2364            TripleQuotes::Yes
2365        } else {
2366            TripleQuotes::No
2367        }
2368    }
2369
2370    fn prefix(self) -> AnyStringPrefix {
2371        let AnyStringFlags(flags) = self;
2372
2373        // f-strings
2374        if flags.contains(AnyStringFlagsInner::F_PREFIX) {
2375            if flags.contains(AnyStringFlagsInner::R_PREFIX_LOWER) {
2376                return AnyStringPrefix::Format(FStringPrefix::Raw { uppercase_r: false });
2377            }
2378            if flags.contains(AnyStringFlagsInner::R_PREFIX_UPPER) {
2379                return AnyStringPrefix::Format(FStringPrefix::Raw { uppercase_r: true });
2380            }
2381            return AnyStringPrefix::Format(FStringPrefix::Regular);
2382        }
2383
2384        // t-strings
2385        if flags.contains(AnyStringFlagsInner::T_PREFIX) {
2386            if flags.contains(AnyStringFlagsInner::R_PREFIX_LOWER) {
2387                return AnyStringPrefix::Template(TStringPrefix::Raw { uppercase_r: false });
2388            }
2389            if flags.contains(AnyStringFlagsInner::R_PREFIX_UPPER) {
2390                return AnyStringPrefix::Template(TStringPrefix::Raw { uppercase_r: true });
2391            }
2392            return AnyStringPrefix::Template(TStringPrefix::Regular);
2393        }
2394
2395        // bytestrings
2396        if flags.contains(AnyStringFlagsInner::B_PREFIX) {
2397            if flags.contains(AnyStringFlagsInner::R_PREFIX_LOWER) {
2398                return AnyStringPrefix::Bytes(ByteStringPrefix::Raw { uppercase_r: false });
2399            }
2400            if flags.contains(AnyStringFlagsInner::R_PREFIX_UPPER) {
2401                return AnyStringPrefix::Bytes(ByteStringPrefix::Raw { uppercase_r: true });
2402            }
2403            return AnyStringPrefix::Bytes(ByteStringPrefix::Regular);
2404        }
2405
2406        // all other strings
2407        if flags.contains(AnyStringFlagsInner::R_PREFIX_LOWER) {
2408            return AnyStringPrefix::Regular(StringLiteralPrefix::Raw { uppercase: false });
2409        }
2410        if flags.contains(AnyStringFlagsInner::R_PREFIX_UPPER) {
2411            return AnyStringPrefix::Regular(StringLiteralPrefix::Raw { uppercase: true });
2412        }
2413        if flags.contains(AnyStringFlagsInner::U_PREFIX) {
2414            return AnyStringPrefix::Regular(StringLiteralPrefix::Unicode);
2415        }
2416        AnyStringPrefix::Regular(StringLiteralPrefix::Empty)
2417    }
2418
2419    fn is_unclosed(self) -> bool {
2420        self.0.intersects(AnyStringFlagsInner::UNCLOSED)
2421    }
2422}
2423
2424impl fmt::Debug for AnyStringFlags {
2425    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2426        f.debug_struct("AnyStringFlags")
2427            .field("prefix", &self.prefix())
2428            .field("triple_quoted", &self.is_triple_quoted())
2429            .field("quote_style", &self.quote_style())
2430            .field("unclosed", &self.is_unclosed())
2431            .finish()
2432    }
2433}
2434
2435impl From<AnyStringFlags> for StringLiteralFlags {
2436    fn from(value: AnyStringFlags) -> StringLiteralFlags {
2437        let AnyStringPrefix::Regular(prefix) = value.prefix() else {
2438            unreachable!(
2439                "Should never attempt to convert {} into a regular string",
2440                value.prefix()
2441            )
2442        };
2443        StringLiteralFlags::empty()
2444            .with_quote_style(value.quote_style())
2445            .with_prefix(prefix)
2446            .with_triple_quotes(value.triple_quotes())
2447            .with_unclosed(value.is_unclosed())
2448    }
2449}
2450
2451impl From<StringLiteralFlags> for AnyStringFlags {
2452    fn from(value: StringLiteralFlags) -> Self {
2453        value.as_any_string_flags()
2454    }
2455}
2456
2457impl From<AnyStringFlags> for BytesLiteralFlags {
2458    fn from(value: AnyStringFlags) -> BytesLiteralFlags {
2459        let AnyStringPrefix::Bytes(bytestring_prefix) = value.prefix() else {
2460            unreachable!(
2461                "Should never attempt to convert {} into a bytestring",
2462                value.prefix()
2463            )
2464        };
2465        BytesLiteralFlags::empty()
2466            .with_quote_style(value.quote_style())
2467            .with_prefix(bytestring_prefix)
2468            .with_triple_quotes(value.triple_quotes())
2469            .with_unclosed(value.is_unclosed())
2470    }
2471}
2472
2473impl From<BytesLiteralFlags> for AnyStringFlags {
2474    fn from(value: BytesLiteralFlags) -> Self {
2475        value.as_any_string_flags()
2476    }
2477}
2478
2479impl From<AnyStringFlags> for FStringFlags {
2480    fn from(value: AnyStringFlags) -> FStringFlags {
2481        let AnyStringPrefix::Format(prefix) = value.prefix() else {
2482            unreachable!(
2483                "Should never attempt to convert {} into an f-string",
2484                value.prefix()
2485            )
2486        };
2487        FStringFlags::empty()
2488            .with_quote_style(value.quote_style())
2489            .with_prefix(prefix)
2490            .with_triple_quotes(value.triple_quotes())
2491            .with_unclosed(value.is_unclosed())
2492    }
2493}
2494
2495impl From<FStringFlags> for AnyStringFlags {
2496    fn from(value: FStringFlags) -> Self {
2497        value.as_any_string_flags()
2498    }
2499}
2500
2501impl From<AnyStringFlags> for TStringFlags {
2502    fn from(value: AnyStringFlags) -> TStringFlags {
2503        let AnyStringPrefix::Template(prefix) = value.prefix() else {
2504            unreachable!(
2505                "Should never attempt to convert {} into a t-string",
2506                value.prefix()
2507            )
2508        };
2509        TStringFlags::empty()
2510            .with_quote_style(value.quote_style())
2511            .with_prefix(prefix)
2512            .with_triple_quotes(value.triple_quotes())
2513            .with_unclosed(value.is_unclosed())
2514    }
2515}
2516
2517impl From<TStringFlags> for AnyStringFlags {
2518    fn from(value: TStringFlags) -> Self {
2519        value.as_any_string_flags()
2520    }
2521}
2522
2523#[derive(Clone, Debug, PartialEq, is_macro::Is)]
2524#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2525pub enum Number {
2526    Int(int::Int),
2527    Float(f64),
2528    Complex { real: f64, imag: f64 },
2529}
2530
2531impl ExprName {
2532    pub fn id(&self) -> &Name {
2533        &self.id
2534    }
2535
2536    /// Returns `true` if this node represents an invalid name i.e., the `ctx` is [`Invalid`].
2537    ///
2538    /// [`Invalid`]: ExprContext::Invalid
2539    pub const fn is_invalid(&self) -> bool {
2540        matches!(self.ctx, ExprContext::Invalid)
2541    }
2542}
2543
2544impl ExprList {
2545    pub fn iter(&self) -> std::slice::Iter<'_, Expr> {
2546        self.elts.iter()
2547    }
2548
2549    pub fn len(&self) -> usize {
2550        self.elts.len()
2551    }
2552
2553    pub fn is_empty(&self) -> bool {
2554        self.elts.is_empty()
2555    }
2556}
2557
2558impl<'a> IntoIterator for &'a ExprList {
2559    type IntoIter = std::slice::Iter<'a, Expr>;
2560    type Item = &'a Expr;
2561
2562    fn into_iter(self) -> Self::IntoIter {
2563        self.iter()
2564    }
2565}
2566
2567impl ExprTuple {
2568    pub fn iter(&self) -> std::slice::Iter<'_, Expr> {
2569        self.elts.iter()
2570    }
2571
2572    pub fn len(&self) -> usize {
2573        self.elts.len()
2574    }
2575
2576    pub fn is_empty(&self) -> bool {
2577        self.elts.is_empty()
2578    }
2579}
2580
2581impl<'a> IntoIterator for &'a ExprTuple {
2582    type IntoIter = std::slice::Iter<'a, Expr>;
2583    type Item = &'a Expr;
2584
2585    fn into_iter(self) -> Self::IntoIter {
2586        self.iter()
2587    }
2588}
2589
2590/// See also [expr_context](https://docs.python.org/3/library/ast.html#ast.expr_context)
2591#[derive(Clone, Debug, PartialEq, is_macro::Is, Copy, Hash, Eq)]
2592#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2593pub enum ExprContext {
2594    Load,
2595    Store,
2596    Del,
2597    Invalid,
2598}
2599
2600/// See also [boolop](https://docs.python.org/3/library/ast.html#ast.BoolOp)
2601#[derive(Clone, Debug, PartialEq, is_macro::Is, Copy, Hash, Eq)]
2602#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2603pub enum BoolOp {
2604    And,
2605    Or,
2606}
2607
2608impl BoolOp {
2609    pub const fn as_str(&self) -> &'static str {
2610        match self {
2611            BoolOp::And => "and",
2612            BoolOp::Or => "or",
2613        }
2614    }
2615}
2616
2617impl fmt::Display for BoolOp {
2618    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2619        f.write_str(self.as_str())
2620    }
2621}
2622
2623/// See also [operator](https://docs.python.org/3/library/ast.html#ast.operator)
2624#[derive(Clone, Debug, PartialEq, is_macro::Is, Copy, Hash, Eq)]
2625#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2626pub enum Operator {
2627    Add,
2628    Sub,
2629    Mult,
2630    MatMult,
2631    Div,
2632    Mod,
2633    Pow,
2634    LShift,
2635    RShift,
2636    BitOr,
2637    BitXor,
2638    BitAnd,
2639    FloorDiv,
2640}
2641
2642impl Operator {
2643    pub const fn as_str(&self) -> &'static str {
2644        match self {
2645            Operator::Add => "+",
2646            Operator::Sub => "-",
2647            Operator::Mult => "*",
2648            Operator::MatMult => "@",
2649            Operator::Div => "/",
2650            Operator::Mod => "%",
2651            Operator::Pow => "**",
2652            Operator::LShift => "<<",
2653            Operator::RShift => ">>",
2654            Operator::BitOr => "|",
2655            Operator::BitXor => "^",
2656            Operator::BitAnd => "&",
2657            Operator::FloorDiv => "//",
2658        }
2659    }
2660
2661    /// Returns the dunder method name for the operator.
2662    pub const fn dunder(self) -> &'static str {
2663        match self {
2664            Operator::Add => "__add__",
2665            Operator::Sub => "__sub__",
2666            Operator::Mult => "__mul__",
2667            Operator::MatMult => "__matmul__",
2668            Operator::Div => "__truediv__",
2669            Operator::Mod => "__mod__",
2670            Operator::Pow => "__pow__",
2671            Operator::LShift => "__lshift__",
2672            Operator::RShift => "__rshift__",
2673            Operator::BitOr => "__or__",
2674            Operator::BitXor => "__xor__",
2675            Operator::BitAnd => "__and__",
2676            Operator::FloorDiv => "__floordiv__",
2677        }
2678    }
2679
2680    /// Returns the in-place dunder method name for the operator.
2681    pub const fn in_place_dunder(self) -> &'static str {
2682        match self {
2683            Operator::Add => "__iadd__",
2684            Operator::Sub => "__isub__",
2685            Operator::Mult => "__imul__",
2686            Operator::MatMult => "__imatmul__",
2687            Operator::Div => "__itruediv__",
2688            Operator::Mod => "__imod__",
2689            Operator::Pow => "__ipow__",
2690            Operator::LShift => "__ilshift__",
2691            Operator::RShift => "__irshift__",
2692            Operator::BitOr => "__ior__",
2693            Operator::BitXor => "__ixor__",
2694            Operator::BitAnd => "__iand__",
2695            Operator::FloorDiv => "__ifloordiv__",
2696        }
2697    }
2698
2699    /// Returns the reflected dunder method name for the operator.
2700    pub const fn reflected_dunder(self) -> &'static str {
2701        match self {
2702            Operator::Add => "__radd__",
2703            Operator::Sub => "__rsub__",
2704            Operator::Mult => "__rmul__",
2705            Operator::MatMult => "__rmatmul__",
2706            Operator::Div => "__rtruediv__",
2707            Operator::Mod => "__rmod__",
2708            Operator::Pow => "__rpow__",
2709            Operator::LShift => "__rlshift__",
2710            Operator::RShift => "__rrshift__",
2711            Operator::BitOr => "__ror__",
2712            Operator::BitXor => "__rxor__",
2713            Operator::BitAnd => "__rand__",
2714            Operator::FloorDiv => "__rfloordiv__",
2715        }
2716    }
2717}
2718
2719impl fmt::Display for Operator {
2720    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2721        f.write_str(self.as_str())
2722    }
2723}
2724
2725/// See also [unaryop](https://docs.python.org/3/library/ast.html#ast.unaryop)
2726#[derive(Clone, Debug, PartialEq, is_macro::Is, Copy, Hash, Eq)]
2727#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2728pub enum UnaryOp {
2729    Invert,
2730    Not,
2731    UAdd,
2732    USub,
2733}
2734
2735impl UnaryOp {
2736    pub const fn as_str(&self) -> &'static str {
2737        match self {
2738            UnaryOp::Invert => "~",
2739            UnaryOp::Not => "not",
2740            UnaryOp::UAdd => "+",
2741            UnaryOp::USub => "-",
2742        }
2743    }
2744}
2745
2746impl fmt::Display for UnaryOp {
2747    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2748        f.write_str(self.as_str())
2749    }
2750}
2751
2752/// See also [cmpop](https://docs.python.org/3/library/ast.html#ast.cmpop)
2753#[derive(Clone, Debug, PartialEq, is_macro::Is, Copy, Hash, Eq)]
2754#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2755pub enum CmpOp {
2756    Eq,
2757    NotEq,
2758    Lt,
2759    LtE,
2760    Gt,
2761    GtE,
2762    Is,
2763    IsNot,
2764    In,
2765    NotIn,
2766}
2767
2768impl CmpOp {
2769    pub const fn as_str(&self) -> &'static str {
2770        match self {
2771            CmpOp::Eq => "==",
2772            CmpOp::NotEq => "!=",
2773            CmpOp::Lt => "<",
2774            CmpOp::LtE => "<=",
2775            CmpOp::Gt => ">",
2776            CmpOp::GtE => ">=",
2777            CmpOp::Is => "is",
2778            CmpOp::IsNot => "is not",
2779            CmpOp::In => "in",
2780            CmpOp::NotIn => "not in",
2781        }
2782    }
2783
2784    #[must_use]
2785    pub const fn negate(&self) -> Self {
2786        match self {
2787            CmpOp::Eq => CmpOp::NotEq,
2788            CmpOp::NotEq => CmpOp::Eq,
2789            CmpOp::Lt => CmpOp::GtE,
2790            CmpOp::LtE => CmpOp::Gt,
2791            CmpOp::Gt => CmpOp::LtE,
2792            CmpOp::GtE => CmpOp::Lt,
2793            CmpOp::Is => CmpOp::IsNot,
2794            CmpOp::IsNot => CmpOp::Is,
2795            CmpOp::In => CmpOp::NotIn,
2796            CmpOp::NotIn => CmpOp::In,
2797        }
2798    }
2799}
2800
2801impl fmt::Display for CmpOp {
2802    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2803        f.write_str(self.as_str())
2804    }
2805}
2806
2807/// See also [comprehension](https://docs.python.org/3/library/ast.html#ast.comprehension)
2808#[derive(Clone, Debug, PartialEq)]
2809#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2810pub struct Comprehension {
2811    pub range: TextRange,
2812    pub node_index: AtomicNodeIndex,
2813    pub target: Expr,
2814    pub iter: Expr,
2815    pub ifs: Vec<Expr>,
2816    pub is_async: bool,
2817}
2818
2819/// See also [ExceptHandler](https://docs.python.org/3/library/ast.html#ast.ExceptHandler)
2820#[derive(Clone, Debug, PartialEq)]
2821#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2822pub struct ExceptHandlerExceptHandler {
2823    pub range: TextRange,
2824    pub node_index: AtomicNodeIndex,
2825    pub type_: Option<Box<Expr>>,
2826    pub name: Option<Identifier>,
2827    pub body: Suite,
2828}
2829
2830/// See also [arg](https://docs.python.org/3/library/ast.html#ast.arg)
2831#[derive(Clone, Debug, PartialEq)]
2832#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2833pub struct Parameter {
2834    pub range: TextRange,
2835    pub node_index: AtomicNodeIndex,
2836    pub name: Identifier,
2837    pub annotation: Option<Box<Expr>>,
2838}
2839
2840impl Parameter {
2841    pub const fn name(&self) -> &Identifier {
2842        &self.name
2843    }
2844
2845    pub fn annotation(&self) -> Option<&Expr> {
2846        self.annotation.as_deref()
2847    }
2848}
2849
2850/// See also [keyword](https://docs.python.org/3/library/ast.html#ast.keyword)
2851#[derive(Clone, Debug, PartialEq)]
2852#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2853pub struct Keyword {
2854    pub range: TextRange,
2855    pub node_index: AtomicNodeIndex,
2856    pub arg: Option<Identifier>,
2857    pub value: Expr,
2858}
2859
2860/// See also [alias](https://docs.python.org/3/library/ast.html#ast.alias)
2861#[derive(Clone, Debug, PartialEq)]
2862#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2863pub struct Alias {
2864    pub range: TextRange,
2865    pub node_index: AtomicNodeIndex,
2866    pub name: Identifier,
2867    pub asname: Option<Identifier>,
2868}
2869
2870/// See also [withitem](https://docs.python.org/3/library/ast.html#ast.withitem)
2871#[derive(Clone, Debug, PartialEq)]
2872#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2873pub struct WithItem {
2874    pub range: TextRange,
2875    pub node_index: AtomicNodeIndex,
2876    pub context_expr: Expr,
2877    pub optional_vars: Option<Box<Expr>>,
2878}
2879
2880/// See also [match_case](https://docs.python.org/3/library/ast.html#ast.match_case)
2881#[derive(Clone, Debug, PartialEq)]
2882#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2883pub struct MatchCase {
2884    pub range: TextRange,
2885    pub node_index: AtomicNodeIndex,
2886    pub pattern: Pattern,
2887    pub guard: Option<Box<Expr>>,
2888    pub body: Suite,
2889}
2890
2891impl Pattern {
2892    /// Checks if the [`Pattern`] is an [irrefutable pattern].
2893    ///
2894    /// [irrefutable pattern]: https://peps.python.org/pep-0634/#irrefutable-case-blocks
2895    pub fn is_irrefutable(&self) -> bool {
2896        self.irrefutable_pattern().is_some()
2897    }
2898
2899    /// Return `Some(IrrefutablePattern)` if `self` is irrefutable or `None` otherwise.
2900    pub fn irrefutable_pattern(&self) -> Option<IrrefutablePattern> {
2901        match self {
2902            Pattern::MatchAs(PatternMatchAs {
2903                pattern,
2904                name,
2905                range,
2906                node_index,
2907            }) => match pattern {
2908                Some(pattern) => pattern.irrefutable_pattern(),
2909                None => match name {
2910                    Some(name) => Some(IrrefutablePattern {
2911                        kind: IrrefutablePatternKind::Name(name.id.clone()),
2912                        range: *range,
2913                        node_index: node_index.clone(),
2914                    }),
2915                    None => Some(IrrefutablePattern {
2916                        kind: IrrefutablePatternKind::Wildcard,
2917                        range: *range,
2918                        node_index: node_index.clone(),
2919                    }),
2920                },
2921            },
2922            Pattern::MatchOr(PatternMatchOr { patterns, .. }) => {
2923                patterns.iter().find_map(Pattern::irrefutable_pattern)
2924            }
2925            _ => None,
2926        }
2927    }
2928
2929    /// Checks if the [`Pattern`] is a [wildcard pattern].
2930    ///
2931    /// The following are wildcard patterns:
2932    /// ```python
2933    /// match subject:
2934    ///     case _ as x: ...
2935    ///     case _ | _: ...
2936    ///     case _: ...
2937    /// ```
2938    ///
2939    /// [wildcard pattern]: https://docs.python.org/3/reference/compound_stmts.html#wildcard-patterns
2940    pub fn is_wildcard(&self) -> bool {
2941        match self {
2942            Pattern::MatchAs(PatternMatchAs { pattern, .. }) => {
2943                pattern.as_deref().is_none_or(Pattern::is_wildcard)
2944            }
2945            Pattern::MatchOr(PatternMatchOr { patterns, .. }) => {
2946                patterns.iter().all(Pattern::is_wildcard)
2947            }
2948            _ => false,
2949        }
2950    }
2951}
2952
2953pub struct IrrefutablePattern {
2954    pub kind: IrrefutablePatternKind,
2955    pub range: TextRange,
2956    pub node_index: AtomicNodeIndex,
2957}
2958
2959#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2960#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2961pub enum IrrefutablePatternKind {
2962    Name(Name),
2963    Wildcard,
2964}
2965
2966/// An AST node to represent the arguments to a [`crate::PatternMatchClass`], i.e., the
2967/// parenthesized contents in `case Point(1, x=0, y=0)`.
2968///
2969/// Like [`Arguments`], but for [`crate::PatternMatchClass`].
2970#[derive(Clone, Debug, PartialEq)]
2971#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2972pub struct PatternArguments {
2973    pub range: TextRange,
2974    pub node_index: AtomicNodeIndex,
2975    pub patterns: ThinVec<Pattern>,
2976    pub keywords: Vec<PatternKeyword>,
2977}
2978
2979/// An AST node to represent the keyword arguments to a [`crate::PatternMatchClass`], i.e., the
2980/// `x=0` and `y=0` in `case Point(x=0, y=0)`.
2981///
2982/// Like [`Keyword`], but for [`crate::PatternMatchClass`].
2983#[derive(Clone, Debug, PartialEq)]
2984#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2985pub struct PatternKeyword {
2986    pub range: TextRange,
2987    pub node_index: AtomicNodeIndex,
2988    pub attr: Identifier,
2989    pub pattern: Pattern,
2990}
2991
2992impl PatternArguments {
2993    /// Returns an iterator over the patterns and keywords in source order.
2994    pub fn iter_source_order(&self) -> PatternArgumentsSourceOrder<'_> {
2995        PatternArgumentsSourceOrder {
2996            patterns: &self.patterns,
2997            keywords: &self.keywords,
2998            next_pattern: 0,
2999            next_keyword: 0,
3000        }
3001    }
3002}
3003
3004/// The iterator returned by [`PatternArguments::iter_source_order`].
3005#[derive(Clone)]
3006pub struct PatternArgumentsSourceOrder<'a> {
3007    patterns: &'a [Pattern],
3008    keywords: &'a [PatternKeyword],
3009    next_pattern: usize,
3010    next_keyword: usize,
3011}
3012
3013/// An entry in the argument list of a class pattern.
3014#[derive(Copy, Clone, Debug, PartialEq)]
3015pub enum PatternOrKeyword<'a> {
3016    Pattern(&'a Pattern),
3017    Keyword(&'a PatternKeyword),
3018}
3019
3020impl<'a> Iterator for PatternArgumentsSourceOrder<'a> {
3021    type Item = PatternOrKeyword<'a>;
3022
3023    fn next(&mut self) -> Option<Self::Item> {
3024        let pattern = self.patterns.get(self.next_pattern);
3025        let keyword = self.keywords.get(self.next_keyword);
3026
3027        if let Some(pattern) = pattern
3028            && keyword.is_none_or(|keyword| pattern.start() <= keyword.start())
3029        {
3030            self.next_pattern += 1;
3031            Some(PatternOrKeyword::Pattern(pattern))
3032        } else if let Some(keyword) = keyword {
3033            self.next_keyword += 1;
3034            Some(PatternOrKeyword::Keyword(keyword))
3035        } else {
3036            None
3037        }
3038    }
3039}
3040
3041impl FusedIterator for PatternArgumentsSourceOrder<'_> {}
3042
3043impl TypeParam {
3044    pub const fn name(&self) -> &Identifier {
3045        match self {
3046            Self::TypeVar(x) => &x.name,
3047            Self::ParamSpec(x) => &x.name,
3048            Self::TypeVarTuple(x) => &x.name,
3049        }
3050    }
3051
3052    pub fn default(&self) -> Option<&Expr> {
3053        match self {
3054            Self::TypeVar(x) => x.default.as_deref(),
3055            Self::ParamSpec(x) => x.default.as_deref(),
3056            Self::TypeVarTuple(x) => x.default.as_deref(),
3057        }
3058    }
3059}
3060
3061/// See also [decorator](https://docs.python.org/3/library/ast.html#ast.decorator)
3062#[derive(Clone, Debug, PartialEq)]
3063#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
3064pub struct Decorator {
3065    pub range: TextRange,
3066    pub node_index: AtomicNodeIndex,
3067    pub expression: Expr,
3068}
3069
3070/// Enumeration of the two kinds of parameter
3071#[derive(Debug, PartialEq, Clone, Copy)]
3072pub enum AnyParameterRef<'a> {
3073    /// Variadic parameters cannot have default values,
3074    /// e.g. both `*args` and `**kwargs` in the following function:
3075    ///
3076    /// ```python
3077    /// def foo(*args, **kwargs): pass
3078    /// ```
3079    Variadic(&'a Parameter),
3080
3081    /// Non-variadic parameters can have default values,
3082    /// though they won't necessarily always have them:
3083    ///
3084    /// ```python
3085    /// def bar(a=1, /, b=2, *, c=3): pass
3086    /// ```
3087    NonVariadic(&'a ParameterWithDefault),
3088}
3089
3090impl<'a> AnyParameterRef<'a> {
3091    pub const fn as_parameter(self) -> &'a Parameter {
3092        match self {
3093            Self::NonVariadic(param) => &param.parameter,
3094            Self::Variadic(param) => param,
3095        }
3096    }
3097
3098    pub const fn name(self) -> &'a Identifier {
3099        &self.as_parameter().name
3100    }
3101
3102    pub const fn is_variadic(self) -> bool {
3103        matches!(self, Self::Variadic(_))
3104    }
3105
3106    pub fn annotation(self) -> Option<&'a Expr> {
3107        self.as_parameter().annotation.as_deref()
3108    }
3109
3110    pub fn default(self) -> Option<&'a Expr> {
3111        match self {
3112            Self::NonVariadic(param) => param.default.as_deref(),
3113            Self::Variadic(_) => None,
3114        }
3115    }
3116}
3117
3118impl Ranged for AnyParameterRef<'_> {
3119    fn range(&self) -> TextRange {
3120        match self {
3121            Self::NonVariadic(param) => param.range,
3122            Self::Variadic(param) => param.range,
3123        }
3124    }
3125}
3126
3127/// An alternative type of AST `arguments`. This is ruff_python_parser-friendly and human-friendly definition of function arguments.
3128/// This form also has advantage to implement pre-order traverse.
3129///
3130/// `defaults` and `kw_defaults` fields are removed and the default values are placed under each [`ParameterWithDefault`] typed argument.
3131/// `vararg` and `kwarg` are still typed as `arg` because they never can have a default value.
3132///
3133/// The original Python-style AST type orders `kwonlyargs` fields by default existence; [Parameters] has location-ordered `kwonlyargs` fields.
3134///
3135/// NOTE: This type differs from the original Python AST. See: [arguments](https://docs.python.org/3/library/ast.html#ast.arguments).
3136
3137#[derive(Clone, Debug, PartialEq, Default)]
3138#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
3139pub struct Parameters {
3140    pub range: TextRange,
3141    pub node_index: AtomicNodeIndex,
3142    pub posonlyargs: ThinVec<ParameterWithDefault>,
3143    pub args: ThinVec<ParameterWithDefault>,
3144    pub vararg: Option<Box<Parameter>>,
3145    pub kwonlyargs: ThinVec<ParameterWithDefault>,
3146    pub kwarg: Option<Box<Parameter>>,
3147}
3148
3149impl Parameters {
3150    /// Returns an iterator over all non-variadic parameters included in this [`Parameters`] node.
3151    ///
3152    /// The variadic parameters (`.vararg` and `.kwarg`) can never have default values;
3153    /// non-variadic parameters sometimes will.
3154    pub fn iter_non_variadic_params(&self) -> impl Iterator<Item = &ParameterWithDefault> {
3155        self.posonlyargs
3156            .iter()
3157            .chain(&self.args)
3158            .chain(&self.kwonlyargs)
3159    }
3160
3161    /// Returns the [`ParameterWithDefault`] with the given name, or `None` if no such [`ParameterWithDefault`] exists.
3162    pub fn find(&self, name: &str) -> Option<&ParameterWithDefault> {
3163        self.iter_non_variadic_params()
3164            .find(|arg| arg.parameter.name.as_str() == name)
3165    }
3166
3167    /// Returns the index of the parameter with the given name
3168    pub fn index(&self, name: &str) -> Option<usize> {
3169        self.iter_non_variadic_params()
3170            .position(|arg| arg.parameter.name.as_str() == name)
3171    }
3172
3173    /// Returns an iterator over all parameters included in this [`Parameters`] node.
3174    pub fn iter(&self) -> ParametersIterator<'_> {
3175        ParametersIterator::new(self)
3176    }
3177
3178    /// Returns the total number of parameters included in this [`Parameters`] node.
3179    pub fn len(&self) -> usize {
3180        let Parameters {
3181            range: _,
3182            node_index: _,
3183            posonlyargs,
3184            args,
3185            vararg,
3186            kwonlyargs,
3187            kwarg,
3188        } = self;
3189        // Safety: a Python function can have an arbitrary number of parameters,
3190        // so theoretically this could be a number that wouldn't fit into a usize,
3191        // which would lead to a panic. A Python function with that many parameters
3192        // is extremely unlikely outside of generated code, however, and it's even
3193        // more unlikely that we'd find a function with that many parameters in a
3194        // source-code file <=4GB large (Ruff's maximum).
3195        posonlyargs
3196            .len()
3197            .checked_add(args.len())
3198            .and_then(|length| length.checked_add(usize::from(vararg.is_some())))
3199            .and_then(|length| length.checked_add(kwonlyargs.len()))
3200            .and_then(|length| length.checked_add(usize::from(kwarg.is_some())))
3201            .expect("Failed to fit the number of parameters into a usize")
3202    }
3203
3204    /// Returns `true` if a parameter with the given name is included in this [`Parameters`].
3205    pub fn includes(&self, name: &str) -> bool {
3206        self.iter().any(|param| param.name() == name)
3207    }
3208
3209    /// Returns `true` if the [`Parameters`] is empty.
3210    pub fn is_empty(&self) -> bool {
3211        self.posonlyargs.is_empty()
3212            && self.args.is_empty()
3213            && self.kwonlyargs.is_empty()
3214            && self.vararg.is_none()
3215            && self.kwarg.is_none()
3216    }
3217
3218    /// Returns an iterator over all parameters in source order.
3219    ///
3220    /// This differs from [`Parameters::iter`] which returns parameters
3221    /// in type-based order (positional-only, regular, variadic, keyword-only,
3222    /// keyword). For well-formed Python the two orderings are identical, but
3223    /// error recovery can produce ASTs where variadic parameters appear before
3224    /// non-variadic ones (e.g. `def foo(**kwargs, a):`).
3225    pub fn iter_source_order(&self) -> ParametersSourceOrderIterator<'_> {
3226        let mut variadics = [self.vararg.as_deref(), self.kwarg.as_deref()];
3227        variadics.sort_by_key(|param| param.map_or(TextSize::new(u32::MAX), Ranged::start));
3228
3229        ParametersSourceOrderIterator {
3230            next_non_variadic_peeked: None,
3231            posonlyargs: self.posonlyargs.iter(),
3232            args: self.args.iter(),
3233            kwonlyargs: self.kwonlyargs.iter(),
3234            variadics,
3235            next_variadic: 0,
3236        }
3237    }
3238}
3239
3240pub struct ParametersIterator<'a> {
3241    posonlyargs: Iter<'a, ParameterWithDefault>,
3242    args: Iter<'a, ParameterWithDefault>,
3243    vararg: Option<&'a Parameter>,
3244    kwonlyargs: Iter<'a, ParameterWithDefault>,
3245    kwarg: Option<&'a Parameter>,
3246}
3247
3248impl<'a> ParametersIterator<'a> {
3249    fn new(parameters: &'a Parameters) -> Self {
3250        let Parameters {
3251            range: _,
3252            node_index: _,
3253            posonlyargs,
3254            args,
3255            vararg,
3256            kwonlyargs,
3257            kwarg,
3258        } = parameters;
3259        Self {
3260            posonlyargs: posonlyargs.iter(),
3261            args: args.iter(),
3262            vararg: vararg.as_deref(),
3263            kwonlyargs: kwonlyargs.iter(),
3264            kwarg: kwarg.as_deref(),
3265        }
3266    }
3267}
3268
3269impl<'a> Iterator for ParametersIterator<'a> {
3270    type Item = AnyParameterRef<'a>;
3271
3272    fn next(&mut self) -> Option<Self::Item> {
3273        let ParametersIterator {
3274            posonlyargs,
3275            args,
3276            vararg,
3277            kwonlyargs,
3278            kwarg,
3279        } = self;
3280
3281        if let Some(param) = posonlyargs.next() {
3282            return Some(AnyParameterRef::NonVariadic(param));
3283        }
3284        if let Some(param) = args.next() {
3285            return Some(AnyParameterRef::NonVariadic(param));
3286        }
3287        if let Some(param) = vararg.take() {
3288            return Some(AnyParameterRef::Variadic(param));
3289        }
3290        if let Some(param) = kwonlyargs.next() {
3291            return Some(AnyParameterRef::NonVariadic(param));
3292        }
3293        kwarg.take().map(AnyParameterRef::Variadic)
3294    }
3295
3296    fn size_hint(&self) -> (usize, Option<usize>) {
3297        let ParametersIterator {
3298            posonlyargs,
3299            args,
3300            vararg,
3301            kwonlyargs,
3302            kwarg,
3303        } = self;
3304
3305        let posonlyargs_len = posonlyargs.len();
3306        let args_len = args.len();
3307        let vararg_len = usize::from(vararg.is_some());
3308        let kwonlyargs_len = kwonlyargs.len();
3309        let kwarg_len = usize::from(kwarg.is_some());
3310
3311        let lower = posonlyargs_len
3312            .saturating_add(args_len)
3313            .saturating_add(vararg_len)
3314            .saturating_add(kwonlyargs_len)
3315            .saturating_add(kwarg_len);
3316
3317        let upper = posonlyargs_len
3318            .checked_add(args_len)
3319            .and_then(|length| length.checked_add(vararg_len))
3320            .and_then(|length| length.checked_add(kwonlyargs_len))
3321            .and_then(|length| length.checked_add(kwarg_len));
3322
3323        (lower, upper)
3324    }
3325
3326    fn last(mut self) -> Option<Self::Item> {
3327        self.next_back()
3328    }
3329}
3330
3331impl DoubleEndedIterator for ParametersIterator<'_> {
3332    fn next_back(&mut self) -> Option<Self::Item> {
3333        let ParametersIterator {
3334            posonlyargs,
3335            args,
3336            vararg,
3337            kwonlyargs,
3338            kwarg,
3339        } = self;
3340
3341        if let Some(param) = kwarg.take() {
3342            return Some(AnyParameterRef::Variadic(param));
3343        }
3344        if let Some(param) = kwonlyargs.next_back() {
3345            return Some(AnyParameterRef::NonVariadic(param));
3346        }
3347        if let Some(param) = vararg.take() {
3348            return Some(AnyParameterRef::Variadic(param));
3349        }
3350        if let Some(param) = args.next_back() {
3351            return Some(AnyParameterRef::NonVariadic(param));
3352        }
3353        posonlyargs.next_back().map(AnyParameterRef::NonVariadic)
3354    }
3355}
3356
3357impl FusedIterator for ParametersIterator<'_> {}
3358
3359/// We rely on the same invariants outlined in the comment above `Parameters::len()`
3360/// in order to implement `ExactSizeIterator` here
3361impl ExactSizeIterator for ParametersIterator<'_> {}
3362
3363impl<'a> IntoIterator for &'a Parameters {
3364    type IntoIter = ParametersIterator<'a>;
3365    type Item = AnyParameterRef<'a>;
3366    fn into_iter(self) -> Self::IntoIter {
3367        self.iter()
3368    }
3369}
3370
3371impl<'a> IntoIterator for &'a Box<Parameters> {
3372    type IntoIter = ParametersIterator<'a>;
3373    type Item = AnyParameterRef<'a>;
3374    fn into_iter(self) -> Self::IntoIter {
3375        (&**self).into_iter()
3376    }
3377}
3378
3379/// The iterator returned by [`Parameters::iter_source_order`].
3380pub struct ParametersSourceOrderIterator<'a> {
3381    next_non_variadic_peeked: Option<&'a ParameterWithDefault>,
3382    posonlyargs: Iter<'a, ParameterWithDefault>,
3383    args: Iter<'a, ParameterWithDefault>,
3384    kwonlyargs: Iter<'a, ParameterWithDefault>,
3385    variadics: [Option<&'a Parameter>; 2],
3386    next_variadic: usize,
3387}
3388
3389impl<'a> ParametersSourceOrderIterator<'a> {
3390    /// Returns the next variadic parameter that appears before `before`, if any.
3391    fn next_variadic_before(&mut self, before: TextSize) -> Option<&'a Parameter> {
3392        let param = self.variadics.get(self.next_variadic).copied().flatten()?;
3393        if param.start() < before {
3394            self.next_variadic += 1;
3395            Some(param)
3396        } else {
3397            None
3398        }
3399    }
3400
3401    fn next_non_variadic(&mut self) -> Option<&'a ParameterWithDefault> {
3402        self.next_non_variadic_peeked
3403            .take()
3404            .or_else(|| self.posonlyargs.next())
3405            .or_else(|| self.args.next())
3406            .or_else(|| self.kwonlyargs.next())
3407    }
3408
3409    fn peek_next_non_variadic(&mut self) -> Option<&'a ParameterWithDefault> {
3410        let next = self.next_non_variadic()?;
3411        self.next_non_variadic_peeked = Some(next);
3412        Some(next)
3413    }
3414}
3415
3416impl<'a> Iterator for ParametersSourceOrderIterator<'a> {
3417    type Item = AnyParameterRef<'a>;
3418
3419    fn next(&mut self) -> Option<Self::Item> {
3420        // If there's a variadic parameter that comes before the next
3421        // non-variadic parameter, emit it first.
3422        let next_non_variadic_start = self
3423            .peek_next_non_variadic()
3424            .map_or(TextSize::new(u32::MAX), Ranged::start);
3425
3426        if let Some(variadic) = self.next_variadic_before(next_non_variadic_start) {
3427            return Some(AnyParameterRef::Variadic(variadic));
3428        }
3429
3430        if let Some(non_variadic) = self.next_non_variadic() {
3431            return Some(AnyParameterRef::NonVariadic(non_variadic));
3432        }
3433
3434        // Drain remaining variadics.
3435        self.next_variadic_before(TextSize::new(u32::MAX))
3436            .map(AnyParameterRef::Variadic)
3437    }
3438}
3439
3440impl FusedIterator for ParametersSourceOrderIterator<'_> {}
3441
3442/// An alternative type of AST `arg`. This is used for each function argument that might have a default value.
3443/// Used by `Arguments` original type.
3444///
3445/// NOTE: This type is different from original Python AST.
3446#[derive(Clone, Debug, PartialEq)]
3447#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
3448pub struct ParameterWithDefault {
3449    pub range: TextRange,
3450    pub node_index: AtomicNodeIndex,
3451    pub parameter: Parameter,
3452    pub default: Option<Box<Expr>>,
3453}
3454
3455impl ParameterWithDefault {
3456    pub fn default(&self) -> Option<&Expr> {
3457        self.default.as_deref()
3458    }
3459
3460    pub const fn name(&self) -> &Identifier {
3461        self.parameter.name()
3462    }
3463
3464    pub fn annotation(&self) -> Option<&Expr> {
3465        self.parameter.annotation()
3466    }
3467
3468    /// Return `true` if the parameter name uses the pre-PEP-570 convention
3469    /// (specified in PEP 484) to indicate to a type checker that it should be treated
3470    /// as positional-only.
3471    pub fn uses_pep_484_positional_only_convention(&self) -> bool {
3472        let name = self.name();
3473        name.starts_with("__") && !name.ends_with("__")
3474    }
3475}
3476
3477/// An AST node used to represent the arguments passed to a function call or class definition.
3478///
3479/// For example, given:
3480/// ```python
3481/// foo(1, 2, 3, bar=4, baz=5)
3482/// ```
3483/// The `Arguments` node would span from the left to right parentheses (inclusive), and contain
3484/// the arguments and keyword arguments in the order they appear in the source code.
3485///
3486/// Similarly, given:
3487/// ```python
3488/// class Foo(Bar, baz=1, qux=2):
3489///     pass
3490/// ```
3491/// The `Arguments` node would again span from the left to right parentheses (inclusive), and
3492/// contain the `Bar` argument and the `baz` and `qux` keyword arguments in the order they
3493/// appear in the source code.
3494///
3495/// In the context of a class definition, the Python-style AST refers to the arguments as `bases`,
3496/// as they represent the "explicitly specified base classes", while the keyword arguments are
3497/// typically used for `metaclass`, with any additional arguments being passed to the `metaclass`.
3498
3499#[derive(Clone, Debug, PartialEq)]
3500#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
3501pub struct Arguments {
3502    pub range: TextRange,
3503    pub node_index: AtomicNodeIndex,
3504    pub args: Box<[Expr]>,
3505    pub keywords: ThinVec<Keyword>,
3506}
3507
3508/// An entry in the argument list of a function call.
3509#[derive(Copy, Clone, Debug, PartialEq)]
3510pub enum ArgOrKeyword<'a> {
3511    Arg(&'a Expr),
3512    Keyword(&'a Keyword),
3513}
3514
3515impl<'a> ArgOrKeyword<'a> {
3516    pub const fn value(self) -> &'a Expr {
3517        match self {
3518            ArgOrKeyword::Arg(argument) => argument,
3519            ArgOrKeyword::Keyword(keyword) => &keyword.value,
3520        }
3521    }
3522
3523    pub const fn is_variadic(self) -> bool {
3524        match self {
3525            ArgOrKeyword::Arg(expr) => expr.is_starred_expr(),
3526            ArgOrKeyword::Keyword(keyword) => keyword.arg.is_none(),
3527        }
3528    }
3529
3530    pub const fn as_variadic(self) -> Option<&'a Keyword> {
3531        match self {
3532            ArgOrKeyword::Keyword(keyword) if keyword.arg.is_none() => Some(keyword),
3533            _ => None,
3534        }
3535    }
3536
3537    pub const fn as_keyword(self) -> Option<&'a Keyword> {
3538        match self {
3539            ArgOrKeyword::Keyword(keyword) => Some(keyword),
3540            ArgOrKeyword::Arg(_) => None,
3541        }
3542    }
3543}
3544
3545impl<'a> From<&'a Expr> for ArgOrKeyword<'a> {
3546    fn from(arg: &'a Expr) -> Self {
3547        Self::Arg(arg)
3548    }
3549}
3550
3551impl<'a> From<&'a Keyword> for ArgOrKeyword<'a> {
3552    fn from(keyword: &'a Keyword) -> Self {
3553        Self::Keyword(keyword)
3554    }
3555}
3556
3557impl Ranged for ArgOrKeyword<'_> {
3558    fn range(&self) -> TextRange {
3559        match self {
3560            Self::Arg(arg) => arg.range(),
3561            Self::Keyword(keyword) => keyword.range(),
3562        }
3563    }
3564}
3565
3566impl Arguments {
3567    /// Return the number of positional and keyword arguments.
3568    pub fn len(&self) -> usize {
3569        self.args.len() + self.keywords.len()
3570    }
3571
3572    /// Return `true` if there are no positional or keyword arguments.
3573    pub fn is_empty(&self) -> bool {
3574        self.len() == 0
3575    }
3576
3577    /// Return the [`Keyword`] with the given name, or `None` if no such [`Keyword`] exists.
3578    pub fn find_keyword(&self, keyword_name: &str) -> Option<&Keyword> {
3579        self.keywords.iter().find(|keyword| {
3580            let Keyword { arg, .. } = keyword;
3581            arg.as_ref().is_some_and(|arg| arg == keyword_name)
3582        })
3583    }
3584
3585    /// Return the positional argument at the given index, or `None` if no such argument exists.
3586    pub fn find_positional(&self, position: usize) -> Option<&Expr> {
3587        self.args
3588            .iter()
3589            .take_while(|expr| !expr.is_starred_expr())
3590            .nth(position)
3591    }
3592
3593    /// Return the value for the argument with the given name or at the given position, or `None` if no such
3594    /// argument exists. Used to retrieve argument values that can be provided _either_ as keyword or
3595    /// positional arguments.
3596    pub fn find_argument_value(&self, name: &str, position: usize) -> Option<&Expr> {
3597        self.find_argument(name, position).map(ArgOrKeyword::value)
3598    }
3599
3600    /// Return the argument with the given name or at the given position, or `None` if no such
3601    /// argument exists. Used to retrieve arguments that can be provided _either_ as keyword or
3602    /// positional arguments.
3603    pub fn find_argument(&self, name: &str, position: usize) -> Option<ArgOrKeyword<'_>> {
3604        self.find_keyword(name)
3605            .map(ArgOrKeyword::from)
3606            .or_else(|| self.find_positional(position).map(ArgOrKeyword::from))
3607    }
3608
3609    /// Iterates over the positional and keyword arguments in the order of declaration.
3610    ///
3611    /// Positional arguments are generally before keyword arguments, but star arguments are an
3612    /// exception:
3613    /// ```python
3614    /// class A(*args, a=2, *args2, **kwargs):
3615    ///     pass
3616    ///
3617    /// f(*args, a=2, *args2, **kwargs)
3618    /// ```
3619    /// where `*args` and `args2` are `args` while `a=1` and `kwargs` are `keywords`.
3620    ///
3621    /// If you would just chain `args` and `keywords` the call would get reordered which we don't
3622    /// want. This function instead "merge sorts" them into the correct order.
3623    ///
3624    /// Note that the order of evaluation is always first `args`, then `keywords`:
3625    /// ```python
3626    /// def f(*args, **kwargs):
3627    ///     pass
3628    ///
3629    /// def g(x):
3630    ///     print(x)
3631    ///     return x
3632    ///
3633    ///
3634    /// f(*g([1]), a=g(2), *g([3]), **g({"4": 5}))
3635    /// ```
3636    /// Output:
3637    /// ```text
3638    /// [1]
3639    /// [3]
3640    /// 2
3641    /// {'4': 5}
3642    /// ```
3643    pub fn iter_source_order(&self) -> ArgumentsSourceOrder<'_> {
3644        ArgumentsSourceOrder {
3645            args: &self.args,
3646            keywords: &self.keywords,
3647            next_arg: 0,
3648            next_keyword: 0,
3649        }
3650    }
3651
3652    pub fn inner_range(&self) -> TextRange {
3653        TextRange::new(self.l_paren_range().end(), self.r_paren_range().start())
3654    }
3655
3656    pub fn l_paren_range(&self) -> TextRange {
3657        TextRange::at(self.start(), '('.text_len())
3658    }
3659
3660    pub fn r_paren_range(&self) -> TextRange {
3661        TextRange::new(self.end() - ')'.text_len(), self.end())
3662    }
3663}
3664
3665/// The iterator returned by [`Arguments::iter_source_order`].
3666#[derive(Clone)]
3667pub struct ArgumentsSourceOrder<'a> {
3668    args: &'a [Expr],
3669    keywords: &'a [Keyword],
3670    next_arg: usize,
3671    next_keyword: usize,
3672}
3673
3674impl<'a> Iterator for ArgumentsSourceOrder<'a> {
3675    type Item = ArgOrKeyword<'a>;
3676
3677    fn next(&mut self) -> Option<Self::Item> {
3678        let arg = self.args.get(self.next_arg);
3679        let keyword = self.keywords.get(self.next_keyword);
3680
3681        if let Some(arg) = arg
3682            && keyword.is_none_or(|keyword| arg.start() <= keyword.start())
3683        {
3684            self.next_arg += 1;
3685            Some(ArgOrKeyword::Arg(arg))
3686        } else if let Some(keyword) = keyword {
3687            self.next_keyword += 1;
3688            Some(ArgOrKeyword::Keyword(keyword))
3689        } else {
3690            None
3691        }
3692    }
3693}
3694
3695impl FusedIterator for ArgumentsSourceOrder<'_> {}
3696
3697/// An AST node used to represent a sequence of type parameters.
3698///
3699/// For example, given:
3700/// ```python
3701/// class C[T, U, V]: ...
3702/// ```
3703/// The `TypeParams` node would span from the left to right brackets (inclusive), and contain
3704/// the `T`, `U`, and `V` type parameters in the order they appear in the source code.
3705
3706#[derive(Clone, Debug, PartialEq)]
3707#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
3708pub struct TypeParams {
3709    pub range: TextRange,
3710    pub node_index: AtomicNodeIndex,
3711    pub type_params: Vec<TypeParam>,
3712}
3713
3714impl Deref for TypeParams {
3715    type Target = [TypeParam];
3716
3717    fn deref(&self) -> &Self::Target {
3718        &self.type_params
3719    }
3720}
3721
3722impl<'a> IntoIterator for &'a TypeParams {
3723    type Item = &'a TypeParam;
3724    type IntoIter = std::slice::Iter<'a, TypeParam>;
3725
3726    fn into_iter(self) -> Self::IntoIter {
3727        self.type_params.iter()
3728    }
3729}
3730
3731/// A suite represents a sequence of [`Stmt`].
3732///
3733/// See: <https://docs.python.org/3/reference/compound_stmts.html#grammar-token-python-grammar-suite>
3734pub type Suite = ThinVec<Stmt>;
3735
3736pub type DecoratorList = ThinVec<Decorator>;
3737
3738pub type Patterns = ThinVec<Pattern>;
3739
3740pub type PatternKeys = ThinVec<Expr>;
3741
3742pub type ParameterWithDefaults = ThinVec<ParameterWithDefault>;
3743
3744/// The kind of escape command as defined in [IPython Syntax] in the IPython codebase.
3745///
3746/// [IPython Syntax]: https://github.com/ipython/ipython/blob/635815e8f1ded5b764d66cacc80bbe25e9e2587f/IPython/core/inputtransformer2.py#L335-L343
3747#[derive(PartialEq, Eq, Debug, Clone, Hash, Copy)]
3748#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
3749pub enum IpyEscapeKind {
3750    /// Send line to underlying system shell (`!`).
3751    Shell,
3752    /// Send line to system shell and capture output (`!!`).
3753    ShCap,
3754    /// Show help on object (`?`).
3755    Help,
3756    /// Show help on object, with extra verbosity (`??`).
3757    Help2,
3758    /// Call magic function (`%`).
3759    Magic,
3760    /// Call cell magic function (`%%`).
3761    Magic2,
3762    /// Call first argument with rest of line as arguments after splitting on whitespace
3763    /// and quote each as string (`,`).
3764    Quote,
3765    /// Call first argument with rest of line as an argument quoted as a single string (`;`).
3766    Quote2,
3767    /// Call first argument with rest of line as arguments (`/`).
3768    Paren,
3769}
3770
3771impl TryFrom<char> for IpyEscapeKind {
3772    type Error = String;
3773
3774    fn try_from(ch: char) -> Result<Self, Self::Error> {
3775        match ch {
3776            '!' => Ok(IpyEscapeKind::Shell),
3777            '?' => Ok(IpyEscapeKind::Help),
3778            '%' => Ok(IpyEscapeKind::Magic),
3779            ',' => Ok(IpyEscapeKind::Quote),
3780            ';' => Ok(IpyEscapeKind::Quote2),
3781            '/' => Ok(IpyEscapeKind::Paren),
3782            _ => Err(format!("Unexpected magic escape: {ch}")),
3783        }
3784    }
3785}
3786
3787impl TryFrom<[char; 2]> for IpyEscapeKind {
3788    type Error = String;
3789
3790    fn try_from(ch: [char; 2]) -> Result<Self, Self::Error> {
3791        match ch {
3792            ['!', '!'] => Ok(IpyEscapeKind::ShCap),
3793            ['?', '?'] => Ok(IpyEscapeKind::Help2),
3794            ['%', '%'] => Ok(IpyEscapeKind::Magic2),
3795            [c1, c2] => Err(format!("Unexpected magic escape: {c1}{c2}")),
3796        }
3797    }
3798}
3799
3800impl fmt::Display for IpyEscapeKind {
3801    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3802        f.write_str(self.as_str())
3803    }
3804}
3805
3806impl IpyEscapeKind {
3807    /// Returns `true` if the escape kind is help i.e., `?` or `??`.
3808    pub const fn is_help(self) -> bool {
3809        matches!(self, IpyEscapeKind::Help | IpyEscapeKind::Help2)
3810    }
3811
3812    /// Returns `true` if the escape kind is magic i.e., `%` or `%%`.
3813    pub const fn is_magic(self) -> bool {
3814        matches!(self, IpyEscapeKind::Magic | IpyEscapeKind::Magic2)
3815    }
3816
3817    pub fn as_str(self) -> &'static str {
3818        match self {
3819            IpyEscapeKind::Shell => "!",
3820            IpyEscapeKind::ShCap => "!!",
3821            IpyEscapeKind::Help => "?",
3822            IpyEscapeKind::Help2 => "??",
3823            IpyEscapeKind::Magic => "%",
3824            IpyEscapeKind::Magic2 => "%%",
3825            IpyEscapeKind::Quote => ",",
3826            IpyEscapeKind::Quote2 => ";",
3827            IpyEscapeKind::Paren => "/",
3828        }
3829    }
3830}
3831
3832/// An `Identifier` with an empty `id` is invalid.
3833///
3834/// For example, in the following code `id` will be empty.
3835/// ```python
3836/// def 1():
3837///     ...
3838/// ```
3839#[derive(Clone, Debug, PartialEq, Eq, Hash)]
3840#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
3841pub struct Identifier {
3842    pub id: Name,
3843    pub range: TextRange,
3844    pub node_index: AtomicNodeIndex,
3845}
3846
3847impl Identifier {
3848    #[inline]
3849    pub fn new(id: impl Into<Name>, range: TextRange) -> Self {
3850        Self {
3851            id: id.into(),
3852            node_index: AtomicNodeIndex::NONE,
3853            range,
3854        }
3855    }
3856
3857    pub fn id(&self) -> &Name {
3858        &self.id
3859    }
3860
3861    pub fn is_valid(&self) -> bool {
3862        !self.id.is_empty()
3863    }
3864}
3865
3866impl Identifier {
3867    #[inline]
3868    pub fn as_str(&self) -> &str {
3869        self.id.as_str()
3870    }
3871}
3872
3873impl PartialEq<str> for Identifier {
3874    #[inline]
3875    fn eq(&self, other: &str) -> bool {
3876        self.id == other
3877    }
3878}
3879
3880impl PartialEq<String> for Identifier {
3881    #[inline]
3882    fn eq(&self, other: &String) -> bool {
3883        self.id == other
3884    }
3885}
3886
3887impl std::ops::Deref for Identifier {
3888    type Target = str;
3889    #[inline]
3890    fn deref(&self) -> &Self::Target {
3891        self.id.as_str()
3892    }
3893}
3894
3895impl AsRef<str> for Identifier {
3896    #[inline]
3897    fn as_ref(&self) -> &str {
3898        self.id.as_str()
3899    }
3900}
3901
3902impl std::fmt::Display for Identifier {
3903    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3904        std::fmt::Display::fmt(&self.id, f)
3905    }
3906}
3907
3908impl From<Identifier> for Name {
3909    #[inline]
3910    fn from(identifier: Identifier) -> Name {
3911        identifier.id
3912    }
3913}
3914
3915#[derive(Clone, Copy, Debug, Hash, PartialEq)]
3916#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
3917pub enum Singleton {
3918    None,
3919    True,
3920    False,
3921}
3922
3923impl From<bool> for Singleton {
3924    fn from(value: bool) -> Self {
3925        if value {
3926            Singleton::True
3927        } else {
3928            Singleton::False
3929        }
3930    }
3931}
3932
3933#[cfg(test)]
3934mod tests {
3935    use crate::generated::*;
3936    use crate::{Arguments, Mod, Parameters};
3937
3938    #[test]
3939    #[cfg(target_pointer_width = "64")]
3940    fn size() {
3941        assert_eq!(std::mem::size_of::<Stmt>(), 88);
3942        assert_eq!(std::mem::size_of::<StmtFunctionDef>(), 88);
3943        assert_eq!(std::mem::size_of::<StmtClassDef>(), 80);
3944        assert_eq!(std::mem::size_of::<StmtTry>(), 64);
3945        assert_eq!(std::mem::size_of::<Mod>(), 32);
3946        assert_eq!(std::mem::size_of::<Pattern>(), 72);
3947        assert_eq!(std::mem::size_of::<Parameters>(), 56);
3948        assert_eq!(std::mem::size_of::<Arguments>(), 40);
3949        assert_eq!(std::mem::size_of::<Expr>(), 64);
3950        assert_eq!(std::mem::size_of::<ExprAttribute>(), 56);
3951        assert_eq!(std::mem::size_of::<ExprAwait>(), 24);
3952        assert_eq!(std::mem::size_of::<ExprBinOp>(), 32);
3953        assert_eq!(std::mem::size_of::<ExprBoolOp>(), 40);
3954        assert_eq!(std::mem::size_of::<ExprBooleanLiteral>(), 16);
3955        assert_eq!(std::mem::size_of::<ExprBytesLiteral>(), 48);
3956        assert_eq!(std::mem::size_of::<ExprCall>(), 56);
3957        assert_eq!(std::mem::size_of::<ExprCompare>(), 56);
3958        assert_eq!(std::mem::size_of::<ExprDict>(), 40);
3959        assert_eq!(std::mem::size_of::<ExprDictComp>(), 56);
3960        assert_eq!(std::mem::size_of::<ExprEllipsisLiteral>(), 12);
3961        assert_eq!(std::mem::size_of::<ExprFString>(), 56);
3962        assert_eq!(std::mem::size_of::<ExprGenerator>(), 48);
3963        assert_eq!(std::mem::size_of::<ExprIf>(), 40);
3964        assert_eq!(std::mem::size_of::<ExprIpyEscapeCommand>(), 32);
3965        assert_eq!(std::mem::size_of::<ExprLambda>(), 32);
3966        assert_eq!(std::mem::size_of::<ExprList>(), 40);
3967        assert_eq!(std::mem::size_of::<ExprListComp>(), 48);
3968        assert_eq!(std::mem::size_of::<ExprName>(), 32);
3969        assert_eq!(std::mem::size_of::<ExprNamed>(), 32);
3970        assert_eq!(std::mem::size_of::<ExprNoneLiteral>(), 12);
3971        assert_eq!(std::mem::size_of::<ExprNumberLiteral>(), 40);
3972        assert_eq!(std::mem::size_of::<ExprSet>(), 40);
3973        assert_eq!(std::mem::size_of::<ExprSetComp>(), 48);
3974        assert_eq!(std::mem::size_of::<ExprSlice>(), 40);
3975        assert_eq!(std::mem::size_of::<ExprStarred>(), 24);
3976        assert_eq!(std::mem::size_of::<ExprStringLiteral>(), 48);
3977        assert_eq!(std::mem::size_of::<ExprSubscript>(), 32);
3978        assert_eq!(std::mem::size_of::<ExprTuple>(), 40);
3979        assert_eq!(std::mem::size_of::<ExprUnaryOp>(), 24);
3980        assert_eq!(std::mem::size_of::<ExprYield>(), 24);
3981        assert_eq!(std::mem::size_of::<ExprYieldFrom>(), 24);
3982    }
3983}