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, ExprDict, ExprFString, ExprList, ExprName, ExprSet, ExprStringLiteral,
6    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
1331/// The value representing a [`ExprStringLiteral`].
1332#[derive(Clone, Debug, PartialEq)]
1333#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1334pub struct StringLiteralValue {
1335    inner: StringLiteralValueInner,
1336}
1337
1338impl StringLiteralValue {
1339    /// Creates a new string literal with a single [`StringLiteral`] part.
1340    pub fn single(string: StringLiteral) -> Self {
1341        Self {
1342            inner: StringLiteralValueInner::Single(string),
1343        }
1344    }
1345
1346    /// Returns the [`StringLiteralFlags`] associated with this string literal.
1347    ///
1348    /// For an implicitly concatenated string, it returns the flags for the first literal.
1349    pub fn first_literal_flags(&self) -> StringLiteralFlags {
1350        self.iter()
1351            .next()
1352            .expect(
1353                "There should always be at least one string literal in an `ExprStringLiteral` node",
1354            )
1355            .flags
1356    }
1357
1358    /// Creates a new string literal with the given values that represents an
1359    /// implicitly concatenated strings.
1360    ///
1361    /// # Panics
1362    ///
1363    /// Panics if `strings` has less than 2 elements.
1364    /// Use [`StringLiteralValue::single`] instead.
1365    pub fn concatenated(strings: Vec<StringLiteral>) -> Self {
1366        assert!(
1367            strings.len() > 1,
1368            "Use `StringLiteralValue::single` to create single-part strings"
1369        );
1370        Self {
1371            inner: StringLiteralValueInner::Concatenated(ConcatenatedStringLiteral {
1372                strings,
1373                value: OnceLock::new(),
1374            }),
1375        }
1376    }
1377
1378    /// Returns `true` if the string literal is implicitly concatenated.
1379    pub const fn is_implicit_concatenated(&self) -> bool {
1380        matches!(self.inner, StringLiteralValueInner::Concatenated(_))
1381    }
1382
1383    /// Returns `true` if the string literal has a `u` prefix, e.g. `u"foo"`.
1384    ///
1385    /// Although all strings in Python 3 are valid unicode (and the `u` prefix
1386    /// is only retained for backwards compatibility), these strings are known as
1387    /// "unicode strings".
1388    ///
1389    /// For an implicitly concatenated string, it returns `true` only if the first
1390    /// [`StringLiteral`] has the `u` prefix.
1391    pub fn is_unicode(&self) -> bool {
1392        self.iter()
1393            .next()
1394            .is_some_and(|part| part.flags.prefix().is_unicode())
1395    }
1396
1397    /// Returns a slice of all the [`StringLiteral`] parts contained in this value.
1398    pub fn as_slice(&self) -> &[StringLiteral] {
1399        match &self.inner {
1400            StringLiteralValueInner::Single(value) => std::slice::from_ref(value),
1401            StringLiteralValueInner::Concatenated(value) => value.strings.as_slice(),
1402        }
1403    }
1404
1405    /// Returns a mutable slice of all the [`StringLiteral`] parts contained in this value.
1406    fn as_mut_slice(&mut self) -> &mut [StringLiteral] {
1407        match &mut self.inner {
1408            StringLiteralValueInner::Single(value) => std::slice::from_mut(value),
1409            StringLiteralValueInner::Concatenated(value) => value.strings.as_mut_slice(),
1410        }
1411    }
1412
1413    /// Returns an iterator over all the [`StringLiteral`] parts contained in this value.
1414    pub fn iter(&self) -> Iter<'_, StringLiteral> {
1415        self.as_slice().iter()
1416    }
1417
1418    /// Returns an iterator over all the [`StringLiteral`] parts contained in this value
1419    /// that allows modification.
1420    pub fn iter_mut(&mut self) -> IterMut<'_, StringLiteral> {
1421        self.as_mut_slice().iter_mut()
1422    }
1423
1424    /// Returns `true` if the node represents an empty string.
1425    ///
1426    /// Note that a [`StringLiteralValue`] node will always have >=1 [`StringLiteral`] parts
1427    /// inside it. This method checks whether the value of the concatenated parts is equal
1428    /// to the empty string, not whether the string has 0 parts inside it.
1429    pub fn is_empty(&self) -> bool {
1430        self.len() == 0
1431    }
1432
1433    /// Returns the total length of the string literal value, in bytes, not
1434    /// [`char`]s or graphemes.
1435    pub fn len(&self) -> usize {
1436        self.iter().fold(0, |acc, part| acc + part.value.len())
1437    }
1438
1439    /// Returns an iterator over the [`char`]s of each string literal part.
1440    pub fn chars(&self) -> impl Iterator<Item = char> + Clone + '_ {
1441        self.iter().flat_map(|part| part.value.chars())
1442    }
1443
1444    /// Returns the concatenated string value as a [`str`].
1445    ///
1446    /// Note that this will perform an allocation on the first invocation if the
1447    /// string value is implicitly concatenated.
1448    pub fn to_str(&self) -> &str {
1449        match &self.inner {
1450            StringLiteralValueInner::Single(value) => value.as_str(),
1451            StringLiteralValueInner::Concatenated(value) => value.to_str(),
1452        }
1453    }
1454}
1455
1456impl<'a> IntoIterator for &'a StringLiteralValue {
1457    type Item = &'a StringLiteral;
1458    type IntoIter = Iter<'a, StringLiteral>;
1459
1460    fn into_iter(self) -> Self::IntoIter {
1461        self.iter()
1462    }
1463}
1464
1465impl<'a> IntoIterator for &'a mut StringLiteralValue {
1466    type Item = &'a mut StringLiteral;
1467    type IntoIter = IterMut<'a, StringLiteral>;
1468    fn into_iter(self) -> Self::IntoIter {
1469        self.iter_mut()
1470    }
1471}
1472
1473impl PartialEq<str> for StringLiteralValue {
1474    fn eq(&self, other: &str) -> bool {
1475        if self.len() != other.len() {
1476            return false;
1477        }
1478        // The `zip` here is safe because we have checked the length of both parts.
1479        self.chars().zip(other.chars()).all(|(c1, c2)| c1 == c2)
1480    }
1481}
1482
1483impl fmt::Display for StringLiteralValue {
1484    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1485        f.write_str(self.to_str())
1486    }
1487}
1488
1489/// An internal representation of [`StringLiteralValue`].
1490#[derive(Clone, Debug, PartialEq)]
1491#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1492enum StringLiteralValueInner {
1493    /// A single string literal i.e., `"foo"`.
1494    Single(StringLiteral),
1495
1496    /// An implicitly concatenated string literals i.e., `"foo" "bar"`.
1497    Concatenated(ConcatenatedStringLiteral),
1498}
1499
1500bitflags! {
1501    #[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
1502    struct StringLiteralFlagsInner: u8 {
1503        /// The string uses double quotes (e.g. `"foo"`).
1504        /// If this flag is not set, the string uses single quotes (`'foo'`).
1505        const DOUBLE = 1 << 0;
1506
1507        /// The string is triple-quoted (`"""foo"""`):
1508        /// it begins and ends with three consecutive quote characters.
1509        const TRIPLE_QUOTED = 1 << 1;
1510
1511        /// The string has a `u` or `U` prefix, e.g. `u"foo"`.
1512        /// While this prefix is a no-op at runtime,
1513        /// strings with this prefix can have no other prefixes set;
1514        /// it is therefore invalid for this flag to be set
1515        /// if `R_PREFIX` is also set.
1516        const U_PREFIX = 1 << 2;
1517
1518        /// The string has an `r` prefix, meaning it is a raw string
1519        /// with a lowercase 'r' (e.g. `r"foo\."`).
1520        /// It is invalid to set this flag if `U_PREFIX` is also set.
1521        const R_PREFIX_LOWER = 1 << 3;
1522
1523        /// The string has an `R` prefix, meaning it is a raw string
1524        /// with an uppercase 'R' (e.g. `R'foo\d'`).
1525        /// See https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#r-strings-and-r-strings
1526        /// for why we track the casing of the `r` prefix,
1527        /// but not for any other prefix
1528        const R_PREFIX_UPPER = 1 << 4;
1529
1530        /// The string was deemed invalid by the parser.
1531        const INVALID = 1 << 5;
1532
1533        /// The string literal misses the matching closing quote(s).
1534        const UNCLOSED = 1 << 6;
1535    }
1536}
1537
1538#[cfg(feature = "get-size")]
1539impl get_size2::GetSize for StringLiteralFlagsInner {}
1540
1541/// Flags that can be queried to obtain information
1542/// regarding the prefixes and quotes used for a string literal.
1543///
1544/// ## Notes on usage
1545///
1546/// If you're using a `Generator` from the `ruff_python_codegen` crate to generate a lint-rule fix
1547/// from an existing string literal, consider passing along the [`StringLiteral::flags`] field or
1548/// the result of the [`StringLiteralValue::first_literal_flags`] method. If you don't have an
1549/// existing string but have a `Checker` from the `ruff_linter` crate available, consider using
1550/// `Checker::default_string_flags` to create instances of this struct; this method will properly
1551/// handle surrounding f-strings. For usage that doesn't fit into one of these categories, the
1552/// public constructor [`StringLiteralFlags::empty`] can be used.
1553#[derive(Copy, Clone, Eq, PartialEq, Hash)]
1554#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1555pub struct StringLiteralFlags(StringLiteralFlagsInner);
1556
1557impl StringLiteralFlags {
1558    /// Construct a new [`StringLiteralFlags`] with **no flags set**.
1559    ///
1560    /// See [`StringLiteralFlags::with_quote_style`], [`StringLiteralFlags::with_triple_quotes`],
1561    /// and [`StringLiteralFlags::with_prefix`] for ways of setting the quote style (single or
1562    /// double), enabling triple quotes, and adding prefixes (such as `r` or `u`), respectively.
1563    ///
1564    /// See the documentation for [`StringLiteralFlags`] for additional caveats on this constructor,
1565    /// and situations in which alternative ways to construct this struct should be used, especially
1566    /// when writing lint rules.
1567    pub fn empty() -> Self {
1568        Self(StringLiteralFlagsInner::empty())
1569    }
1570
1571    #[must_use]
1572    pub fn with_quote_style(mut self, quote_style: Quote) -> Self {
1573        self.0
1574            .set(StringLiteralFlagsInner::DOUBLE, quote_style.is_double());
1575        self
1576    }
1577
1578    #[must_use]
1579    pub fn with_triple_quotes(mut self, triple_quotes: TripleQuotes) -> Self {
1580        self.0.set(
1581            StringLiteralFlagsInner::TRIPLE_QUOTED,
1582            triple_quotes.is_yes(),
1583        );
1584        self
1585    }
1586
1587    #[must_use]
1588    pub fn with_unclosed(mut self, unclosed: bool) -> Self {
1589        self.0.set(StringLiteralFlagsInner::UNCLOSED, unclosed);
1590        self
1591    }
1592
1593    #[must_use]
1594    pub fn with_prefix(self, prefix: StringLiteralPrefix) -> Self {
1595        let StringLiteralFlags(flags) = self;
1596        match prefix {
1597            StringLiteralPrefix::Empty => Self(
1598                flags
1599                    - StringLiteralFlagsInner::R_PREFIX_LOWER
1600                    - StringLiteralFlagsInner::R_PREFIX_UPPER
1601                    - StringLiteralFlagsInner::U_PREFIX,
1602            ),
1603            StringLiteralPrefix::Raw { uppercase: false } => Self(
1604                (flags | StringLiteralFlagsInner::R_PREFIX_LOWER)
1605                    - StringLiteralFlagsInner::R_PREFIX_UPPER
1606                    - StringLiteralFlagsInner::U_PREFIX,
1607            ),
1608            StringLiteralPrefix::Raw { uppercase: true } => Self(
1609                (flags | StringLiteralFlagsInner::R_PREFIX_UPPER)
1610                    - StringLiteralFlagsInner::R_PREFIX_LOWER
1611                    - StringLiteralFlagsInner::U_PREFIX,
1612            ),
1613            StringLiteralPrefix::Unicode => Self(
1614                (flags | StringLiteralFlagsInner::U_PREFIX)
1615                    - StringLiteralFlagsInner::R_PREFIX_LOWER
1616                    - StringLiteralFlagsInner::R_PREFIX_UPPER,
1617            ),
1618        }
1619    }
1620
1621    #[must_use]
1622    pub fn with_invalid(mut self) -> Self {
1623        self.0 |= StringLiteralFlagsInner::INVALID;
1624        self
1625    }
1626
1627    pub const fn prefix(self) -> StringLiteralPrefix {
1628        if self.0.contains(StringLiteralFlagsInner::U_PREFIX) {
1629            debug_assert!(
1630                !self.0.intersects(
1631                    StringLiteralFlagsInner::R_PREFIX_LOWER
1632                        .union(StringLiteralFlagsInner::R_PREFIX_UPPER)
1633                )
1634            );
1635            StringLiteralPrefix::Unicode
1636        } else if self.0.contains(StringLiteralFlagsInner::R_PREFIX_LOWER) {
1637            debug_assert!(!self.0.contains(StringLiteralFlagsInner::R_PREFIX_UPPER));
1638            StringLiteralPrefix::Raw { uppercase: false }
1639        } else if self.0.contains(StringLiteralFlagsInner::R_PREFIX_UPPER) {
1640            StringLiteralPrefix::Raw { uppercase: true }
1641        } else {
1642            StringLiteralPrefix::Empty
1643        }
1644    }
1645}
1646
1647impl StringFlags for StringLiteralFlags {
1648    /// Return the quoting style (single or double quotes)
1649    /// used by the string's opener and closer:
1650    /// - `"a"` -> `QuoteStyle::Double`
1651    /// - `'a'` -> `QuoteStyle::Single`
1652    fn quote_style(self) -> Quote {
1653        if self.0.contains(StringLiteralFlagsInner::DOUBLE) {
1654            Quote::Double
1655        } else {
1656            Quote::Single
1657        }
1658    }
1659
1660    /// Return `true` if the string is triple-quoted, i.e.,
1661    /// it begins and ends with three consecutive quote characters.
1662    /// For example: `"""bar"""`
1663    fn triple_quotes(self) -> TripleQuotes {
1664        if self.0.contains(StringLiteralFlagsInner::TRIPLE_QUOTED) {
1665            TripleQuotes::Yes
1666        } else {
1667            TripleQuotes::No
1668        }
1669    }
1670
1671    fn prefix(self) -> AnyStringPrefix {
1672        AnyStringPrefix::Regular(self.prefix())
1673    }
1674
1675    fn is_unclosed(self) -> bool {
1676        self.0.intersects(StringLiteralFlagsInner::UNCLOSED)
1677    }
1678}
1679
1680impl fmt::Debug for StringLiteralFlags {
1681    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1682        f.debug_struct("StringLiteralFlags")
1683            .field("quote_style", &self.quote_style())
1684            .field("prefix", &self.prefix())
1685            .field("triple_quoted", &self.is_triple_quoted())
1686            .field("unclosed", &self.is_unclosed())
1687            .finish()
1688    }
1689}
1690
1691/// An AST node that represents a single string literal which is part of an
1692/// [`ExprStringLiteral`].
1693#[derive(Clone, Debug, PartialEq)]
1694#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1695pub struct StringLiteral {
1696    pub range: TextRange,
1697    pub node_index: AtomicNodeIndex,
1698    pub value: Box<str>,
1699    pub flags: StringLiteralFlags,
1700}
1701
1702impl Deref for StringLiteral {
1703    type Target = str;
1704
1705    fn deref(&self) -> &Self::Target {
1706        &self.value
1707    }
1708}
1709
1710impl StringLiteral {
1711    /// Extracts a string slice containing the entire `String`.
1712    pub fn as_str(&self) -> &str {
1713        self
1714    }
1715
1716    /// Creates an invalid string literal with the given range.
1717    pub fn invalid(range: TextRange) -> Self {
1718        Self {
1719            range,
1720            value: "".into(),
1721            node_index: AtomicNodeIndex::NONE,
1722            flags: StringLiteralFlags::empty().with_invalid(),
1723        }
1724    }
1725
1726    /// The range of the string literal's contents.
1727    ///
1728    /// This excludes any prefixes, opening quotes or closing quotes.
1729    pub fn content_range(&self) -> TextRange {
1730        TextRange::new(
1731            self.start() + self.flags.opener_len(),
1732            self.end() - self.flags.closer_len(),
1733        )
1734    }
1735}
1736
1737impl From<StringLiteral> for Expr {
1738    fn from(payload: StringLiteral) -> Self {
1739        ExprStringLiteral {
1740            range: payload.range,
1741            node_index: AtomicNodeIndex::NONE,
1742            value: StringLiteralValue::single(payload),
1743        }
1744        .into()
1745    }
1746}
1747
1748/// An internal representation of [`StringLiteral`] that represents an
1749/// implicitly concatenated string.
1750#[derive(Clone)]
1751#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1752struct ConcatenatedStringLiteral {
1753    /// The individual [`StringLiteral`] parts that make up the concatenated string.
1754    strings: Vec<StringLiteral>,
1755    /// The concatenated string value.
1756    value: OnceLock<Box<str>>,
1757}
1758
1759impl ConcatenatedStringLiteral {
1760    /// Extracts a string slice containing the entire concatenated string.
1761    fn to_str(&self) -> &str {
1762        self.value.get_or_init(|| {
1763            let concatenated: String = self.strings.iter().map(StringLiteral::as_str).collect();
1764            concatenated.into_boxed_str()
1765        })
1766    }
1767}
1768
1769impl PartialEq for ConcatenatedStringLiteral {
1770    fn eq(&self, other: &Self) -> bool {
1771        if self.strings.len() != other.strings.len() {
1772            return false;
1773        }
1774        // The `zip` here is safe because we have checked the length of both parts.
1775        self.strings
1776            .iter()
1777            .zip(&other.strings)
1778            .all(|(s1, s2)| s1 == s2)
1779    }
1780}
1781
1782impl Debug for ConcatenatedStringLiteral {
1783    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1784        f.debug_struct("ConcatenatedStringLiteral")
1785            .field("strings", &self.strings)
1786            .field("value", &self.to_str())
1787            .finish()
1788    }
1789}
1790
1791impl ExprBytesLiteral {
1792    /// Return `Some(literal)` if the bytestring only consists of a single `BytesLiteral` part
1793    /// (indicating that it is not implicitly concatenated). Otherwise, return `None`.
1794    pub const fn as_single_part_bytestring(&self) -> Option<&BytesLiteral> {
1795        match &self.value.inner {
1796            BytesLiteralValueInner::Single(value) => Some(value),
1797            BytesLiteralValueInner::Concatenated(_) => None,
1798        }
1799    }
1800}
1801
1802/// The value representing a [`ExprBytesLiteral`].
1803#[derive(Clone, Debug, PartialEq)]
1804#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1805pub struct BytesLiteralValue {
1806    inner: BytesLiteralValueInner,
1807}
1808
1809impl BytesLiteralValue {
1810    /// Create a new bytestring literal with a single [`BytesLiteral`] part.
1811    pub fn single(value: BytesLiteral) -> Self {
1812        Self {
1813            inner: BytesLiteralValueInner::Single(value),
1814        }
1815    }
1816
1817    /// Creates a new bytestring literal with the given values that represents an
1818    /// implicitly concatenated bytestring.
1819    ///
1820    /// # Panics
1821    ///
1822    /// Panics if `values` has less than 2 elements.
1823    /// Use [`BytesLiteralValue::single`] instead.
1824    pub fn concatenated(values: Vec<BytesLiteral>) -> Self {
1825        assert!(
1826            values.len() > 1,
1827            "Use `BytesLiteralValue::single` to create single-part bytestrings"
1828        );
1829        Self {
1830            inner: BytesLiteralValueInner::Concatenated(values),
1831        }
1832    }
1833
1834    /// Returns `true` if the bytestring is implicitly concatenated.
1835    pub const fn is_implicit_concatenated(&self) -> bool {
1836        matches!(self.inner, BytesLiteralValueInner::Concatenated(_))
1837    }
1838
1839    /// Returns a slice of all the [`BytesLiteral`] parts contained in this value.
1840    pub fn as_slice(&self) -> &[BytesLiteral] {
1841        match &self.inner {
1842            BytesLiteralValueInner::Single(value) => std::slice::from_ref(value),
1843            BytesLiteralValueInner::Concatenated(value) => value.as_slice(),
1844        }
1845    }
1846
1847    /// Returns a mutable slice of all the [`BytesLiteral`] parts contained in this value.
1848    fn as_mut_slice(&mut self) -> &mut [BytesLiteral] {
1849        match &mut self.inner {
1850            BytesLiteralValueInner::Single(value) => std::slice::from_mut(value),
1851            BytesLiteralValueInner::Concatenated(value) => value.as_mut_slice(),
1852        }
1853    }
1854
1855    /// Returns an iterator over all the [`BytesLiteral`] parts contained in this value.
1856    pub fn iter(&self) -> Iter<'_, BytesLiteral> {
1857        self.as_slice().iter()
1858    }
1859
1860    /// Returns an iterator over all the [`BytesLiteral`] parts contained in this value
1861    /// that allows modification.
1862    pub fn iter_mut(&mut self) -> IterMut<'_, BytesLiteral> {
1863        self.as_mut_slice().iter_mut()
1864    }
1865
1866    /// Return `true` if the node represents an empty bytestring.
1867    ///
1868    /// Note that a [`BytesLiteralValue`] node will always have >=1 [`BytesLiteral`] parts
1869    /// inside it. This method checks whether the value of the concatenated parts is equal
1870    /// to the empty bytestring, not whether the bytestring has 0 parts inside it.
1871    pub fn is_empty(&self) -> bool {
1872        self.iter().all(|part| part.is_empty())
1873    }
1874
1875    /// Returns the length of the concatenated bytestring.
1876    pub fn len(&self) -> usize {
1877        self.iter().map(|part| part.len()).sum()
1878    }
1879
1880    /// Returns an iterator over the bytes of the concatenated bytestring.
1881    pub fn bytes(&self) -> impl Iterator<Item = u8> + '_ {
1882        self.iter().flat_map(|part| part.as_slice().iter().copied())
1883    }
1884}
1885
1886impl<'a> IntoIterator for &'a BytesLiteralValue {
1887    type Item = &'a BytesLiteral;
1888    type IntoIter = Iter<'a, BytesLiteral>;
1889
1890    fn into_iter(self) -> Self::IntoIter {
1891        self.iter()
1892    }
1893}
1894
1895impl<'a> IntoIterator for &'a mut BytesLiteralValue {
1896    type Item = &'a mut BytesLiteral;
1897    type IntoIter = IterMut<'a, BytesLiteral>;
1898    fn into_iter(self) -> Self::IntoIter {
1899        self.iter_mut()
1900    }
1901}
1902
1903impl PartialEq<[u8]> for BytesLiteralValue {
1904    fn eq(&self, other: &[u8]) -> bool {
1905        if self.len() != other.len() {
1906            return false;
1907        }
1908        // The `zip` here is safe because we have checked the length of both parts.
1909        self.bytes()
1910            .zip(other.iter().copied())
1911            .all(|(b1, b2)| b1 == b2)
1912    }
1913}
1914
1915impl<'a> From<&'a BytesLiteralValue> for Cow<'a, [u8]> {
1916    fn from(value: &'a BytesLiteralValue) -> Self {
1917        match &value.inner {
1918            BytesLiteralValueInner::Single(BytesLiteral {
1919                value: bytes_value, ..
1920            }) => Cow::from(bytes_value.as_ref()),
1921            BytesLiteralValueInner::Concatenated(bytes_literal_vec) => Cow::Owned(
1922                bytes_literal_vec
1923                    .iter()
1924                    .flat_map(|bytes_literal| bytes_literal.value.to_vec())
1925                    .collect::<Vec<u8>>(),
1926            ),
1927        }
1928    }
1929}
1930
1931/// An internal representation of [`BytesLiteralValue`].
1932#[derive(Clone, Debug, PartialEq)]
1933#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1934enum BytesLiteralValueInner {
1935    /// A single-part bytestring literal i.e., `b"foo"`.
1936    Single(BytesLiteral),
1937
1938    /// An implicitly concatenated bytestring literal i.e., `b"foo" b"bar"`.
1939    Concatenated(Vec<BytesLiteral>),
1940}
1941
1942bitflags! {
1943    #[derive(Default, Copy, Clone, PartialEq, Eq, Hash)]
1944    struct BytesLiteralFlagsInner: u8 {
1945        /// The bytestring uses double quotes (e.g. `b"foo"`).
1946        /// If this flag is not set, the bytestring uses single quotes (e.g. `b'foo'`).
1947        const DOUBLE = 1 << 0;
1948
1949        /// The bytestring is triple-quoted (e.g. `b"""foo"""`):
1950        /// it begins and ends with three consecutive quote characters.
1951        const TRIPLE_QUOTED = 1 << 1;
1952
1953        /// The bytestring has an `r` prefix (e.g. `rb"foo"`),
1954        /// meaning it is a raw bytestring with a lowercase 'r'.
1955        const R_PREFIX_LOWER = 1 << 2;
1956
1957        /// The bytestring has an `R` prefix (e.g. `Rb"foo"`),
1958        /// meaning it is a raw bytestring with an uppercase 'R'.
1959        /// See https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#r-strings-and-r-strings
1960        /// for why we track the casing of the `r` prefix, but not for any other prefix
1961        const R_PREFIX_UPPER = 1 << 3;
1962
1963        /// The bytestring was deemed invalid by the parser.
1964        const INVALID = 1 << 4;
1965
1966        /// The byte string misses the matching closing quote(s).
1967        const UNCLOSED = 1 << 5;
1968    }
1969}
1970
1971#[cfg(feature = "get-size")]
1972impl get_size2::GetSize for BytesLiteralFlagsInner {}
1973
1974/// Flags that can be queried to obtain information
1975/// regarding the prefixes and quotes used for a bytes literal.
1976///
1977/// ## Notes on usage
1978///
1979/// If you're using a `Generator` from the `ruff_python_codegen` crate to generate a lint-rule fix
1980/// from an existing bytes literal, consider passing along the [`BytesLiteral::flags`] field. If
1981/// you don't have an existing literal but have a `Checker` from the `ruff_linter` crate available,
1982/// consider using `Checker::default_bytes_flags` to create instances of this struct; this method
1983/// will properly handle surrounding f-strings. For usage that doesn't fit into one of these
1984/// categories, the public constructor [`BytesLiteralFlags::empty`] can be used.
1985#[derive(Copy, Clone, Eq, PartialEq, Hash)]
1986#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1987pub struct BytesLiteralFlags(BytesLiteralFlagsInner);
1988
1989impl BytesLiteralFlags {
1990    /// Construct a new [`BytesLiteralFlags`] with **no flags set**.
1991    ///
1992    /// See [`BytesLiteralFlags::with_quote_style`], [`BytesLiteralFlags::with_triple_quotes`], and
1993    /// [`BytesLiteralFlags::with_prefix`] for ways of setting the quote style (single or double),
1994    /// enabling triple quotes, and adding prefixes (such as `r`), respectively.
1995    ///
1996    /// See the documentation for [`BytesLiteralFlags`] for additional caveats on this constructor,
1997    /// and situations in which alternative ways to construct this struct should be used, especially
1998    /// when writing lint rules.
1999    pub fn empty() -> Self {
2000        Self(BytesLiteralFlagsInner::empty())
2001    }
2002
2003    #[must_use]
2004    pub fn with_quote_style(mut self, quote_style: Quote) -> Self {
2005        self.0
2006            .set(BytesLiteralFlagsInner::DOUBLE, quote_style.is_double());
2007        self
2008    }
2009
2010    #[must_use]
2011    pub fn with_triple_quotes(mut self, triple_quotes: TripleQuotes) -> Self {
2012        self.0.set(
2013            BytesLiteralFlagsInner::TRIPLE_QUOTED,
2014            triple_quotes.is_yes(),
2015        );
2016        self
2017    }
2018
2019    #[must_use]
2020    pub fn with_unclosed(mut self, unclosed: bool) -> Self {
2021        self.0.set(BytesLiteralFlagsInner::UNCLOSED, unclosed);
2022        self
2023    }
2024
2025    #[must_use]
2026    pub fn with_prefix(mut self, prefix: ByteStringPrefix) -> Self {
2027        match prefix {
2028            ByteStringPrefix::Regular => {
2029                self.0 -= BytesLiteralFlagsInner::R_PREFIX_LOWER;
2030                self.0 -= BytesLiteralFlagsInner::R_PREFIX_UPPER;
2031            }
2032            ByteStringPrefix::Raw { uppercase_r } => {
2033                self.0
2034                    .set(BytesLiteralFlagsInner::R_PREFIX_UPPER, uppercase_r);
2035                self.0
2036                    .set(BytesLiteralFlagsInner::R_PREFIX_LOWER, !uppercase_r);
2037            }
2038        }
2039        self
2040    }
2041
2042    #[must_use]
2043    pub fn with_invalid(mut self) -> Self {
2044        self.0 |= BytesLiteralFlagsInner::INVALID;
2045        self
2046    }
2047
2048    pub const fn prefix(self) -> ByteStringPrefix {
2049        if self.0.contains(BytesLiteralFlagsInner::R_PREFIX_LOWER) {
2050            debug_assert!(!self.0.contains(BytesLiteralFlagsInner::R_PREFIX_UPPER));
2051            ByteStringPrefix::Raw { uppercase_r: false }
2052        } else if self.0.contains(BytesLiteralFlagsInner::R_PREFIX_UPPER) {
2053            ByteStringPrefix::Raw { uppercase_r: true }
2054        } else {
2055            ByteStringPrefix::Regular
2056        }
2057    }
2058}
2059
2060impl StringFlags for BytesLiteralFlags {
2061    /// Return `true` if the bytestring is triple-quoted, i.e.,
2062    /// it begins and ends with three consecutive quote characters.
2063    /// For example: `b"""{bar}"""`
2064    fn triple_quotes(self) -> TripleQuotes {
2065        if self.0.contains(BytesLiteralFlagsInner::TRIPLE_QUOTED) {
2066            TripleQuotes::Yes
2067        } else {
2068            TripleQuotes::No
2069        }
2070    }
2071
2072    /// Return the quoting style (single or double quotes)
2073    /// used by the bytestring's opener and closer:
2074    /// - `b"a"` -> `QuoteStyle::Double`
2075    /// - `b'a'` -> `QuoteStyle::Single`
2076    fn quote_style(self) -> Quote {
2077        if self.0.contains(BytesLiteralFlagsInner::DOUBLE) {
2078            Quote::Double
2079        } else {
2080            Quote::Single
2081        }
2082    }
2083
2084    fn prefix(self) -> AnyStringPrefix {
2085        AnyStringPrefix::Bytes(self.prefix())
2086    }
2087
2088    fn is_unclosed(self) -> bool {
2089        self.0.intersects(BytesLiteralFlagsInner::UNCLOSED)
2090    }
2091}
2092
2093impl fmt::Debug for BytesLiteralFlags {
2094    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2095        f.debug_struct("BytesLiteralFlags")
2096            .field("quote_style", &self.quote_style())
2097            .field("prefix", &self.prefix())
2098            .field("triple_quoted", &self.is_triple_quoted())
2099            .field("unclosed", &self.is_unclosed())
2100            .finish()
2101    }
2102}
2103
2104/// An AST node that represents a single bytes literal which is part of an
2105/// [`ExprBytesLiteral`].
2106#[derive(Clone, Debug, PartialEq)]
2107#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2108pub struct BytesLiteral {
2109    pub range: TextRange,
2110    pub node_index: AtomicNodeIndex,
2111    pub value: Box<[u8]>,
2112    pub flags: BytesLiteralFlags,
2113}
2114
2115impl Deref for BytesLiteral {
2116    type Target = [u8];
2117
2118    fn deref(&self) -> &Self::Target {
2119        &self.value
2120    }
2121}
2122
2123impl BytesLiteral {
2124    /// Extracts a byte slice containing the entire [`BytesLiteral`].
2125    pub fn as_slice(&self) -> &[u8] {
2126        self
2127    }
2128
2129    /// Creates a new invalid bytes literal with the given range.
2130    pub fn invalid(range: TextRange) -> Self {
2131        Self {
2132            range,
2133            value: Box::new([]),
2134            node_index: AtomicNodeIndex::NONE,
2135            flags: BytesLiteralFlags::empty().with_invalid(),
2136        }
2137    }
2138}
2139
2140impl From<BytesLiteral> for Expr {
2141    fn from(payload: BytesLiteral) -> Self {
2142        ExprBytesLiteral {
2143            range: payload.range,
2144            node_index: AtomicNodeIndex::NONE,
2145            value: BytesLiteralValue::single(payload),
2146        }
2147        .into()
2148    }
2149}
2150
2151bitflags! {
2152    /// Flags that can be queried to obtain information
2153    /// regarding the prefixes and quotes used for a string literal.
2154    ///
2155    /// Note that not all of these flags can be validly combined -- e.g.,
2156    /// it is invalid to combine the `U_PREFIX` flag with any other
2157    /// of the `*_PREFIX` flags. As such, the recommended way to set the
2158    /// prefix flags is by calling the `as_flags()` method on the
2159    /// `StringPrefix` enum.
2160    #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
2161    struct AnyStringFlagsInner: u16 {
2162        /// The string uses double quotes (`"`).
2163        /// If this flag is not set, the string uses single quotes (`'`).
2164        const DOUBLE = 1 << 0;
2165
2166        /// The string is triple-quoted:
2167        /// it begins and ends with three consecutive quote characters.
2168        const TRIPLE_QUOTED = 1 << 1;
2169
2170        /// The string has a `u` or `U` prefix.
2171        /// While this prefix is a no-op at runtime,
2172        /// strings with this prefix can have no other prefixes set.
2173        const U_PREFIX = 1 << 2;
2174
2175        /// The string has a `b` or `B` prefix.
2176        /// This means that the string is a sequence of `int`s at runtime,
2177        /// rather than a sequence of `str`s.
2178        /// Strings with this flag can also be raw strings,
2179        /// but can have no other prefixes.
2180        const B_PREFIX = 1 << 3;
2181
2182        /// The string has a `f` or `F` prefix, meaning it is an f-string.
2183        /// F-strings can also be raw strings,
2184        /// but can have no other prefixes.
2185        const F_PREFIX = 1 << 4;
2186
2187        /// The string has a `t` or `T` prefix, meaning it is a t-string.
2188        /// T-strings can also be raw strings,
2189        /// but can have no other prefixes.
2190        const T_PREFIX = 1 << 5;
2191
2192        /// The string has an `r` prefix, meaning it is a raw string.
2193        /// F-strings and byte-strings can be raw,
2194        /// as can strings with no other prefixes.
2195        /// U-strings cannot be raw.
2196        const R_PREFIX_LOWER = 1 << 6;
2197
2198        /// The string has an `R` prefix, meaning it is a raw string.
2199        /// The casing of the `r`/`R` has no semantic significance at runtime;
2200        /// see https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#r-strings-and-r-strings
2201        /// for why we track the casing of the `r` prefix,
2202        /// but not for any other prefix
2203        const R_PREFIX_UPPER = 1 << 7;
2204
2205        /// String without matching closing quote(s).
2206        const UNCLOSED = 1 << 8;
2207    }
2208}
2209
2210#[derive(Clone, Copy, PartialEq, Eq, Hash)]
2211pub struct AnyStringFlags(AnyStringFlagsInner);
2212
2213impl AnyStringFlags {
2214    #[must_use]
2215    pub fn with_prefix(mut self, prefix: AnyStringPrefix) -> Self {
2216        self.0 |= match prefix {
2217            // regular strings
2218            AnyStringPrefix::Regular(StringLiteralPrefix::Empty) => AnyStringFlagsInner::empty(),
2219            AnyStringPrefix::Regular(StringLiteralPrefix::Unicode) => AnyStringFlagsInner::U_PREFIX,
2220            AnyStringPrefix::Regular(StringLiteralPrefix::Raw { uppercase: false }) => {
2221                AnyStringFlagsInner::R_PREFIX_LOWER
2222            }
2223            AnyStringPrefix::Regular(StringLiteralPrefix::Raw { uppercase: true }) => {
2224                AnyStringFlagsInner::R_PREFIX_UPPER
2225            }
2226
2227            // bytestrings
2228            AnyStringPrefix::Bytes(ByteStringPrefix::Regular) => AnyStringFlagsInner::B_PREFIX,
2229            AnyStringPrefix::Bytes(ByteStringPrefix::Raw { uppercase_r: false }) => {
2230                AnyStringFlagsInner::B_PREFIX.union(AnyStringFlagsInner::R_PREFIX_LOWER)
2231            }
2232            AnyStringPrefix::Bytes(ByteStringPrefix::Raw { uppercase_r: true }) => {
2233                AnyStringFlagsInner::B_PREFIX.union(AnyStringFlagsInner::R_PREFIX_UPPER)
2234            }
2235
2236            // f-strings
2237            AnyStringPrefix::Format(FStringPrefix::Regular) => AnyStringFlagsInner::F_PREFIX,
2238            AnyStringPrefix::Format(FStringPrefix::Raw { uppercase_r: false }) => {
2239                AnyStringFlagsInner::F_PREFIX.union(AnyStringFlagsInner::R_PREFIX_LOWER)
2240            }
2241            AnyStringPrefix::Format(FStringPrefix::Raw { uppercase_r: true }) => {
2242                AnyStringFlagsInner::F_PREFIX.union(AnyStringFlagsInner::R_PREFIX_UPPER)
2243            }
2244
2245            // t-strings
2246            AnyStringPrefix::Template(TStringPrefix::Regular) => AnyStringFlagsInner::T_PREFIX,
2247            AnyStringPrefix::Template(TStringPrefix::Raw { uppercase_r: false }) => {
2248                AnyStringFlagsInner::T_PREFIX.union(AnyStringFlagsInner::R_PREFIX_LOWER)
2249            }
2250            AnyStringPrefix::Template(TStringPrefix::Raw { uppercase_r: true }) => {
2251                AnyStringFlagsInner::T_PREFIX.union(AnyStringFlagsInner::R_PREFIX_UPPER)
2252            }
2253        };
2254        self
2255    }
2256
2257    pub fn new(prefix: AnyStringPrefix, quotes: Quote, triple_quotes: TripleQuotes) -> Self {
2258        Self(AnyStringFlagsInner::empty())
2259            .with_prefix(prefix)
2260            .with_quote_style(quotes)
2261            .with_triple_quotes(triple_quotes)
2262    }
2263
2264    /// Does the string have a `u` or `U` prefix?
2265    pub const fn is_u_string(self) -> bool {
2266        self.0.contains(AnyStringFlagsInner::U_PREFIX)
2267    }
2268
2269    /// Does the string have an `r` or `R` prefix?
2270    pub const fn is_raw_string(self) -> bool {
2271        self.0.intersects(
2272            AnyStringFlagsInner::R_PREFIX_LOWER.union(AnyStringFlagsInner::R_PREFIX_UPPER),
2273        )
2274    }
2275
2276    /// Does the string have an `f`,`F`,`t`, or `T` prefix?
2277    pub const fn is_interpolated_string(self) -> bool {
2278        self.0
2279            .intersects(AnyStringFlagsInner::F_PREFIX.union(AnyStringFlagsInner::T_PREFIX))
2280    }
2281
2282    /// Does the string have a `b` or `B` prefix?
2283    pub const fn is_byte_string(self) -> bool {
2284        self.0.contains(AnyStringFlagsInner::B_PREFIX)
2285    }
2286
2287    #[must_use]
2288    pub fn with_quote_style(mut self, quotes: Quote) -> Self {
2289        match quotes {
2290            Quote::Double => self.0 |= AnyStringFlagsInner::DOUBLE,
2291            Quote::Single => self.0 -= AnyStringFlagsInner::DOUBLE,
2292        }
2293        self
2294    }
2295
2296    #[must_use]
2297    pub fn with_triple_quotes(mut self, triple_quotes: TripleQuotes) -> Self {
2298        self.0
2299            .set(AnyStringFlagsInner::TRIPLE_QUOTED, triple_quotes.is_yes());
2300        self
2301    }
2302
2303    #[must_use]
2304    pub fn with_unclosed(mut self, unclosed: bool) -> Self {
2305        self.0.set(AnyStringFlagsInner::UNCLOSED, unclosed);
2306        self
2307    }
2308}
2309
2310impl StringFlags for AnyStringFlags {
2311    /// Does the string use single or double quotes in its opener and closer?
2312    fn quote_style(self) -> Quote {
2313        if self.0.contains(AnyStringFlagsInner::DOUBLE) {
2314            Quote::Double
2315        } else {
2316            Quote::Single
2317        }
2318    }
2319
2320    fn triple_quotes(self) -> TripleQuotes {
2321        if self.0.contains(AnyStringFlagsInner::TRIPLE_QUOTED) {
2322            TripleQuotes::Yes
2323        } else {
2324            TripleQuotes::No
2325        }
2326    }
2327
2328    fn prefix(self) -> AnyStringPrefix {
2329        let AnyStringFlags(flags) = self;
2330
2331        // f-strings
2332        if flags.contains(AnyStringFlagsInner::F_PREFIX) {
2333            if flags.contains(AnyStringFlagsInner::R_PREFIX_LOWER) {
2334                return AnyStringPrefix::Format(FStringPrefix::Raw { uppercase_r: false });
2335            }
2336            if flags.contains(AnyStringFlagsInner::R_PREFIX_UPPER) {
2337                return AnyStringPrefix::Format(FStringPrefix::Raw { uppercase_r: true });
2338            }
2339            return AnyStringPrefix::Format(FStringPrefix::Regular);
2340        }
2341
2342        // t-strings
2343        if flags.contains(AnyStringFlagsInner::T_PREFIX) {
2344            if flags.contains(AnyStringFlagsInner::R_PREFIX_LOWER) {
2345                return AnyStringPrefix::Template(TStringPrefix::Raw { uppercase_r: false });
2346            }
2347            if flags.contains(AnyStringFlagsInner::R_PREFIX_UPPER) {
2348                return AnyStringPrefix::Template(TStringPrefix::Raw { uppercase_r: true });
2349            }
2350            return AnyStringPrefix::Template(TStringPrefix::Regular);
2351        }
2352
2353        // bytestrings
2354        if flags.contains(AnyStringFlagsInner::B_PREFIX) {
2355            if flags.contains(AnyStringFlagsInner::R_PREFIX_LOWER) {
2356                return AnyStringPrefix::Bytes(ByteStringPrefix::Raw { uppercase_r: false });
2357            }
2358            if flags.contains(AnyStringFlagsInner::R_PREFIX_UPPER) {
2359                return AnyStringPrefix::Bytes(ByteStringPrefix::Raw { uppercase_r: true });
2360            }
2361            return AnyStringPrefix::Bytes(ByteStringPrefix::Regular);
2362        }
2363
2364        // all other strings
2365        if flags.contains(AnyStringFlagsInner::R_PREFIX_LOWER) {
2366            return AnyStringPrefix::Regular(StringLiteralPrefix::Raw { uppercase: false });
2367        }
2368        if flags.contains(AnyStringFlagsInner::R_PREFIX_UPPER) {
2369            return AnyStringPrefix::Regular(StringLiteralPrefix::Raw { uppercase: true });
2370        }
2371        if flags.contains(AnyStringFlagsInner::U_PREFIX) {
2372            return AnyStringPrefix::Regular(StringLiteralPrefix::Unicode);
2373        }
2374        AnyStringPrefix::Regular(StringLiteralPrefix::Empty)
2375    }
2376
2377    fn is_unclosed(self) -> bool {
2378        self.0.intersects(AnyStringFlagsInner::UNCLOSED)
2379    }
2380}
2381
2382impl fmt::Debug for AnyStringFlags {
2383    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2384        f.debug_struct("AnyStringFlags")
2385            .field("prefix", &self.prefix())
2386            .field("triple_quoted", &self.is_triple_quoted())
2387            .field("quote_style", &self.quote_style())
2388            .field("unclosed", &self.is_unclosed())
2389            .finish()
2390    }
2391}
2392
2393impl From<AnyStringFlags> for StringLiteralFlags {
2394    fn from(value: AnyStringFlags) -> StringLiteralFlags {
2395        let AnyStringPrefix::Regular(prefix) = value.prefix() else {
2396            unreachable!(
2397                "Should never attempt to convert {} into a regular string",
2398                value.prefix()
2399            )
2400        };
2401        StringLiteralFlags::empty()
2402            .with_quote_style(value.quote_style())
2403            .with_prefix(prefix)
2404            .with_triple_quotes(value.triple_quotes())
2405            .with_unclosed(value.is_unclosed())
2406    }
2407}
2408
2409impl From<StringLiteralFlags> for AnyStringFlags {
2410    fn from(value: StringLiteralFlags) -> Self {
2411        value.as_any_string_flags()
2412    }
2413}
2414
2415impl From<AnyStringFlags> for BytesLiteralFlags {
2416    fn from(value: AnyStringFlags) -> BytesLiteralFlags {
2417        let AnyStringPrefix::Bytes(bytestring_prefix) = value.prefix() else {
2418            unreachable!(
2419                "Should never attempt to convert {} into a bytestring",
2420                value.prefix()
2421            )
2422        };
2423        BytesLiteralFlags::empty()
2424            .with_quote_style(value.quote_style())
2425            .with_prefix(bytestring_prefix)
2426            .with_triple_quotes(value.triple_quotes())
2427            .with_unclosed(value.is_unclosed())
2428    }
2429}
2430
2431impl From<BytesLiteralFlags> for AnyStringFlags {
2432    fn from(value: BytesLiteralFlags) -> Self {
2433        value.as_any_string_flags()
2434    }
2435}
2436
2437impl From<AnyStringFlags> for FStringFlags {
2438    fn from(value: AnyStringFlags) -> FStringFlags {
2439        let AnyStringPrefix::Format(prefix) = value.prefix() else {
2440            unreachable!(
2441                "Should never attempt to convert {} into an f-string",
2442                value.prefix()
2443            )
2444        };
2445        FStringFlags::empty()
2446            .with_quote_style(value.quote_style())
2447            .with_prefix(prefix)
2448            .with_triple_quotes(value.triple_quotes())
2449            .with_unclosed(value.is_unclosed())
2450    }
2451}
2452
2453impl From<FStringFlags> for AnyStringFlags {
2454    fn from(value: FStringFlags) -> Self {
2455        value.as_any_string_flags()
2456    }
2457}
2458
2459impl From<AnyStringFlags> for TStringFlags {
2460    fn from(value: AnyStringFlags) -> TStringFlags {
2461        let AnyStringPrefix::Template(prefix) = value.prefix() else {
2462            unreachable!(
2463                "Should never attempt to convert {} into a t-string",
2464                value.prefix()
2465            )
2466        };
2467        TStringFlags::empty()
2468            .with_quote_style(value.quote_style())
2469            .with_prefix(prefix)
2470            .with_triple_quotes(value.triple_quotes())
2471            .with_unclosed(value.is_unclosed())
2472    }
2473}
2474
2475impl From<TStringFlags> for AnyStringFlags {
2476    fn from(value: TStringFlags) -> Self {
2477        value.as_any_string_flags()
2478    }
2479}
2480
2481#[derive(Clone, Debug, PartialEq, is_macro::Is)]
2482#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2483pub enum Number {
2484    Int(int::Int),
2485    Float(f64),
2486    Complex { real: f64, imag: f64 },
2487}
2488
2489impl ExprName {
2490    pub fn id(&self) -> &Name {
2491        &self.id
2492    }
2493
2494    /// Returns `true` if this node represents an invalid name i.e., the `ctx` is [`Invalid`].
2495    ///
2496    /// [`Invalid`]: ExprContext::Invalid
2497    pub const fn is_invalid(&self) -> bool {
2498        matches!(self.ctx, ExprContext::Invalid)
2499    }
2500}
2501
2502impl ExprList {
2503    pub fn iter(&self) -> std::slice::Iter<'_, Expr> {
2504        self.elts.iter()
2505    }
2506
2507    pub fn len(&self) -> usize {
2508        self.elts.len()
2509    }
2510
2511    pub fn is_empty(&self) -> bool {
2512        self.elts.is_empty()
2513    }
2514}
2515
2516impl<'a> IntoIterator for &'a ExprList {
2517    type IntoIter = std::slice::Iter<'a, Expr>;
2518    type Item = &'a Expr;
2519
2520    fn into_iter(self) -> Self::IntoIter {
2521        self.iter()
2522    }
2523}
2524
2525impl ExprTuple {
2526    pub fn iter(&self) -> std::slice::Iter<'_, Expr> {
2527        self.elts.iter()
2528    }
2529
2530    pub fn len(&self) -> usize {
2531        self.elts.len()
2532    }
2533
2534    pub fn is_empty(&self) -> bool {
2535        self.elts.is_empty()
2536    }
2537}
2538
2539impl<'a> IntoIterator for &'a ExprTuple {
2540    type IntoIter = std::slice::Iter<'a, Expr>;
2541    type Item = &'a Expr;
2542
2543    fn into_iter(self) -> Self::IntoIter {
2544        self.iter()
2545    }
2546}
2547
2548/// See also [expr_context](https://docs.python.org/3/library/ast.html#ast.expr_context)
2549#[derive(Clone, Debug, PartialEq, is_macro::Is, Copy, Hash, Eq)]
2550#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2551pub enum ExprContext {
2552    Load,
2553    Store,
2554    Del,
2555    Invalid,
2556}
2557
2558/// See also [boolop](https://docs.python.org/3/library/ast.html#ast.BoolOp)
2559#[derive(Clone, Debug, PartialEq, is_macro::Is, Copy, Hash, Eq)]
2560#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2561pub enum BoolOp {
2562    And,
2563    Or,
2564}
2565
2566impl BoolOp {
2567    pub const fn as_str(&self) -> &'static str {
2568        match self {
2569            BoolOp::And => "and",
2570            BoolOp::Or => "or",
2571        }
2572    }
2573}
2574
2575impl fmt::Display for BoolOp {
2576    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2577        f.write_str(self.as_str())
2578    }
2579}
2580
2581/// See also [operator](https://docs.python.org/3/library/ast.html#ast.operator)
2582#[derive(Clone, Debug, PartialEq, is_macro::Is, Copy, Hash, Eq)]
2583#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2584pub enum Operator {
2585    Add,
2586    Sub,
2587    Mult,
2588    MatMult,
2589    Div,
2590    Mod,
2591    Pow,
2592    LShift,
2593    RShift,
2594    BitOr,
2595    BitXor,
2596    BitAnd,
2597    FloorDiv,
2598}
2599
2600impl Operator {
2601    pub const fn as_str(&self) -> &'static str {
2602        match self {
2603            Operator::Add => "+",
2604            Operator::Sub => "-",
2605            Operator::Mult => "*",
2606            Operator::MatMult => "@",
2607            Operator::Div => "/",
2608            Operator::Mod => "%",
2609            Operator::Pow => "**",
2610            Operator::LShift => "<<",
2611            Operator::RShift => ">>",
2612            Operator::BitOr => "|",
2613            Operator::BitXor => "^",
2614            Operator::BitAnd => "&",
2615            Operator::FloorDiv => "//",
2616        }
2617    }
2618
2619    /// Returns the dunder method name for the operator.
2620    pub const fn dunder(self) -> &'static str {
2621        match self {
2622            Operator::Add => "__add__",
2623            Operator::Sub => "__sub__",
2624            Operator::Mult => "__mul__",
2625            Operator::MatMult => "__matmul__",
2626            Operator::Div => "__truediv__",
2627            Operator::Mod => "__mod__",
2628            Operator::Pow => "__pow__",
2629            Operator::LShift => "__lshift__",
2630            Operator::RShift => "__rshift__",
2631            Operator::BitOr => "__or__",
2632            Operator::BitXor => "__xor__",
2633            Operator::BitAnd => "__and__",
2634            Operator::FloorDiv => "__floordiv__",
2635        }
2636    }
2637
2638    /// Returns the in-place dunder method name for the operator.
2639    pub const fn in_place_dunder(self) -> &'static str {
2640        match self {
2641            Operator::Add => "__iadd__",
2642            Operator::Sub => "__isub__",
2643            Operator::Mult => "__imul__",
2644            Operator::MatMult => "__imatmul__",
2645            Operator::Div => "__itruediv__",
2646            Operator::Mod => "__imod__",
2647            Operator::Pow => "__ipow__",
2648            Operator::LShift => "__ilshift__",
2649            Operator::RShift => "__irshift__",
2650            Operator::BitOr => "__ior__",
2651            Operator::BitXor => "__ixor__",
2652            Operator::BitAnd => "__iand__",
2653            Operator::FloorDiv => "__ifloordiv__",
2654        }
2655    }
2656
2657    /// Returns the reflected dunder method name for the operator.
2658    pub const fn reflected_dunder(self) -> &'static str {
2659        match self {
2660            Operator::Add => "__radd__",
2661            Operator::Sub => "__rsub__",
2662            Operator::Mult => "__rmul__",
2663            Operator::MatMult => "__rmatmul__",
2664            Operator::Div => "__rtruediv__",
2665            Operator::Mod => "__rmod__",
2666            Operator::Pow => "__rpow__",
2667            Operator::LShift => "__rlshift__",
2668            Operator::RShift => "__rrshift__",
2669            Operator::BitOr => "__ror__",
2670            Operator::BitXor => "__rxor__",
2671            Operator::BitAnd => "__rand__",
2672            Operator::FloorDiv => "__rfloordiv__",
2673        }
2674    }
2675}
2676
2677impl fmt::Display for Operator {
2678    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2679        f.write_str(self.as_str())
2680    }
2681}
2682
2683/// See also [unaryop](https://docs.python.org/3/library/ast.html#ast.unaryop)
2684#[derive(Clone, Debug, PartialEq, is_macro::Is, Copy, Hash, Eq)]
2685#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2686pub enum UnaryOp {
2687    Invert,
2688    Not,
2689    UAdd,
2690    USub,
2691}
2692
2693impl UnaryOp {
2694    pub const fn as_str(&self) -> &'static str {
2695        match self {
2696            UnaryOp::Invert => "~",
2697            UnaryOp::Not => "not",
2698            UnaryOp::UAdd => "+",
2699            UnaryOp::USub => "-",
2700        }
2701    }
2702}
2703
2704impl fmt::Display for UnaryOp {
2705    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2706        f.write_str(self.as_str())
2707    }
2708}
2709
2710/// See also [cmpop](https://docs.python.org/3/library/ast.html#ast.cmpop)
2711#[derive(Clone, Debug, PartialEq, is_macro::Is, Copy, Hash, Eq)]
2712#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2713pub enum CmpOp {
2714    Eq,
2715    NotEq,
2716    Lt,
2717    LtE,
2718    Gt,
2719    GtE,
2720    Is,
2721    IsNot,
2722    In,
2723    NotIn,
2724}
2725
2726impl CmpOp {
2727    pub const fn as_str(&self) -> &'static str {
2728        match self {
2729            CmpOp::Eq => "==",
2730            CmpOp::NotEq => "!=",
2731            CmpOp::Lt => "<",
2732            CmpOp::LtE => "<=",
2733            CmpOp::Gt => ">",
2734            CmpOp::GtE => ">=",
2735            CmpOp::Is => "is",
2736            CmpOp::IsNot => "is not",
2737            CmpOp::In => "in",
2738            CmpOp::NotIn => "not in",
2739        }
2740    }
2741
2742    #[must_use]
2743    pub const fn negate(&self) -> Self {
2744        match self {
2745            CmpOp::Eq => CmpOp::NotEq,
2746            CmpOp::NotEq => CmpOp::Eq,
2747            CmpOp::Lt => CmpOp::GtE,
2748            CmpOp::LtE => CmpOp::Gt,
2749            CmpOp::Gt => CmpOp::LtE,
2750            CmpOp::GtE => CmpOp::Lt,
2751            CmpOp::Is => CmpOp::IsNot,
2752            CmpOp::IsNot => CmpOp::Is,
2753            CmpOp::In => CmpOp::NotIn,
2754            CmpOp::NotIn => CmpOp::In,
2755        }
2756    }
2757}
2758
2759impl fmt::Display for CmpOp {
2760    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2761        f.write_str(self.as_str())
2762    }
2763}
2764
2765/// See also [comprehension](https://docs.python.org/3/library/ast.html#ast.comprehension)
2766#[derive(Clone, Debug, PartialEq)]
2767#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2768pub struct Comprehension {
2769    pub range: TextRange,
2770    pub node_index: AtomicNodeIndex,
2771    pub target: Expr,
2772    pub iter: Expr,
2773    pub ifs: Vec<Expr>,
2774    pub is_async: bool,
2775}
2776
2777/// See also [ExceptHandler](https://docs.python.org/3/library/ast.html#ast.ExceptHandler)
2778#[derive(Clone, Debug, PartialEq)]
2779#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2780pub struct ExceptHandlerExceptHandler {
2781    pub range: TextRange,
2782    pub node_index: AtomicNodeIndex,
2783    pub type_: Option<Box<Expr>>,
2784    pub name: Option<Identifier>,
2785    pub body: Suite,
2786}
2787
2788/// See also [arg](https://docs.python.org/3/library/ast.html#ast.arg)
2789#[derive(Clone, Debug, PartialEq)]
2790#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2791pub struct Parameter {
2792    pub range: TextRange,
2793    pub node_index: AtomicNodeIndex,
2794    pub name: Identifier,
2795    pub annotation: Option<Box<Expr>>,
2796}
2797
2798impl Parameter {
2799    pub const fn name(&self) -> &Identifier {
2800        &self.name
2801    }
2802
2803    pub fn annotation(&self) -> Option<&Expr> {
2804        self.annotation.as_deref()
2805    }
2806}
2807
2808/// See also [keyword](https://docs.python.org/3/library/ast.html#ast.keyword)
2809#[derive(Clone, Debug, PartialEq)]
2810#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2811pub struct Keyword {
2812    pub range: TextRange,
2813    pub node_index: AtomicNodeIndex,
2814    pub arg: Option<Identifier>,
2815    pub value: Expr,
2816}
2817
2818/// See also [alias](https://docs.python.org/3/library/ast.html#ast.alias)
2819#[derive(Clone, Debug, PartialEq)]
2820#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2821pub struct Alias {
2822    pub range: TextRange,
2823    pub node_index: AtomicNodeIndex,
2824    pub name: Identifier,
2825    pub asname: Option<Identifier>,
2826}
2827
2828/// See also [withitem](https://docs.python.org/3/library/ast.html#ast.withitem)
2829#[derive(Clone, Debug, PartialEq)]
2830#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2831pub struct WithItem {
2832    pub range: TextRange,
2833    pub node_index: AtomicNodeIndex,
2834    pub context_expr: Expr,
2835    pub optional_vars: Option<Box<Expr>>,
2836}
2837
2838/// See also [match_case](https://docs.python.org/3/library/ast.html#ast.match_case)
2839#[derive(Clone, Debug, PartialEq)]
2840#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2841pub struct MatchCase {
2842    pub range: TextRange,
2843    pub node_index: AtomicNodeIndex,
2844    pub pattern: Pattern,
2845    pub guard: Option<Box<Expr>>,
2846    pub body: Suite,
2847}
2848
2849impl Pattern {
2850    /// Checks if the [`Pattern`] is an [irrefutable pattern].
2851    ///
2852    /// [irrefutable pattern]: https://peps.python.org/pep-0634/#irrefutable-case-blocks
2853    pub fn is_irrefutable(&self) -> bool {
2854        self.irrefutable_pattern().is_some()
2855    }
2856
2857    /// Return `Some(IrrefutablePattern)` if `self` is irrefutable or `None` otherwise.
2858    pub fn irrefutable_pattern(&self) -> Option<IrrefutablePattern> {
2859        match self {
2860            Pattern::MatchAs(PatternMatchAs {
2861                pattern,
2862                name,
2863                range,
2864                node_index,
2865            }) => match pattern {
2866                Some(pattern) => pattern.irrefutable_pattern(),
2867                None => match name {
2868                    Some(name) => Some(IrrefutablePattern {
2869                        kind: IrrefutablePatternKind::Name(name.id.clone()),
2870                        range: *range,
2871                        node_index: node_index.clone(),
2872                    }),
2873                    None => Some(IrrefutablePattern {
2874                        kind: IrrefutablePatternKind::Wildcard,
2875                        range: *range,
2876                        node_index: node_index.clone(),
2877                    }),
2878                },
2879            },
2880            Pattern::MatchOr(PatternMatchOr { patterns, .. }) => {
2881                patterns.iter().find_map(Pattern::irrefutable_pattern)
2882            }
2883            _ => None,
2884        }
2885    }
2886
2887    /// Checks if the [`Pattern`] is a [wildcard pattern].
2888    ///
2889    /// The following are wildcard patterns:
2890    /// ```python
2891    /// match subject:
2892    ///     case _ as x: ...
2893    ///     case _ | _: ...
2894    ///     case _: ...
2895    /// ```
2896    ///
2897    /// [wildcard pattern]: https://docs.python.org/3/reference/compound_stmts.html#wildcard-patterns
2898    pub fn is_wildcard(&self) -> bool {
2899        match self {
2900            Pattern::MatchAs(PatternMatchAs { pattern, .. }) => {
2901                pattern.as_deref().is_none_or(Pattern::is_wildcard)
2902            }
2903            Pattern::MatchOr(PatternMatchOr { patterns, .. }) => {
2904                patterns.iter().all(Pattern::is_wildcard)
2905            }
2906            _ => false,
2907        }
2908    }
2909}
2910
2911pub struct IrrefutablePattern {
2912    pub kind: IrrefutablePatternKind,
2913    pub range: TextRange,
2914    pub node_index: AtomicNodeIndex,
2915}
2916
2917#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2918#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2919pub enum IrrefutablePatternKind {
2920    Name(Name),
2921    Wildcard,
2922}
2923
2924/// An AST node to represent the arguments to a [`crate::PatternMatchClass`], i.e., the
2925/// parenthesized contents in `case Point(1, x=0, y=0)`.
2926///
2927/// Like [`Arguments`], but for [`crate::PatternMatchClass`].
2928#[derive(Clone, Debug, PartialEq)]
2929#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2930pub struct PatternArguments {
2931    pub range: TextRange,
2932    pub node_index: AtomicNodeIndex,
2933    pub patterns: ThinVec<Pattern>,
2934    pub keywords: Vec<PatternKeyword>,
2935}
2936
2937/// An AST node to represent the keyword arguments to a [`crate::PatternMatchClass`], i.e., the
2938/// `x=0` and `y=0` in `case Point(x=0, y=0)`.
2939///
2940/// Like [`Keyword`], but for [`crate::PatternMatchClass`].
2941#[derive(Clone, Debug, PartialEq)]
2942#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2943pub struct PatternKeyword {
2944    pub range: TextRange,
2945    pub node_index: AtomicNodeIndex,
2946    pub attr: Identifier,
2947    pub pattern: Pattern,
2948}
2949
2950impl PatternArguments {
2951    /// Returns an iterator over the patterns and keywords in source order.
2952    pub fn iter_source_order(&self) -> PatternArgumentsSourceOrder<'_> {
2953        PatternArgumentsSourceOrder {
2954            patterns: &self.patterns,
2955            keywords: &self.keywords,
2956            next_pattern: 0,
2957            next_keyword: 0,
2958        }
2959    }
2960}
2961
2962/// The iterator returned by [`PatternArguments::iter_source_order`].
2963#[derive(Clone)]
2964pub struct PatternArgumentsSourceOrder<'a> {
2965    patterns: &'a [Pattern],
2966    keywords: &'a [PatternKeyword],
2967    next_pattern: usize,
2968    next_keyword: usize,
2969}
2970
2971/// An entry in the argument list of a class pattern.
2972#[derive(Copy, Clone, Debug, PartialEq)]
2973pub enum PatternOrKeyword<'a> {
2974    Pattern(&'a Pattern),
2975    Keyword(&'a PatternKeyword),
2976}
2977
2978impl<'a> Iterator for PatternArgumentsSourceOrder<'a> {
2979    type Item = PatternOrKeyword<'a>;
2980
2981    fn next(&mut self) -> Option<Self::Item> {
2982        let pattern = self.patterns.get(self.next_pattern);
2983        let keyword = self.keywords.get(self.next_keyword);
2984
2985        if let Some(pattern) = pattern
2986            && keyword.is_none_or(|keyword| pattern.start() <= keyword.start())
2987        {
2988            self.next_pattern += 1;
2989            Some(PatternOrKeyword::Pattern(pattern))
2990        } else if let Some(keyword) = keyword {
2991            self.next_keyword += 1;
2992            Some(PatternOrKeyword::Keyword(keyword))
2993        } else {
2994            None
2995        }
2996    }
2997}
2998
2999impl FusedIterator for PatternArgumentsSourceOrder<'_> {}
3000
3001impl TypeParam {
3002    pub const fn name(&self) -> &Identifier {
3003        match self {
3004            Self::TypeVar(x) => &x.name,
3005            Self::ParamSpec(x) => &x.name,
3006            Self::TypeVarTuple(x) => &x.name,
3007        }
3008    }
3009
3010    pub fn default(&self) -> Option<&Expr> {
3011        match self {
3012            Self::TypeVar(x) => x.default.as_deref(),
3013            Self::ParamSpec(x) => x.default.as_deref(),
3014            Self::TypeVarTuple(x) => x.default.as_deref(),
3015        }
3016    }
3017}
3018
3019/// See also [decorator](https://docs.python.org/3/library/ast.html#ast.decorator)
3020#[derive(Clone, Debug, PartialEq)]
3021#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
3022pub struct Decorator {
3023    pub range: TextRange,
3024    pub node_index: AtomicNodeIndex,
3025    pub expression: Expr,
3026}
3027
3028/// Enumeration of the two kinds of parameter
3029#[derive(Debug, PartialEq, Clone, Copy)]
3030pub enum AnyParameterRef<'a> {
3031    /// Variadic parameters cannot have default values,
3032    /// e.g. both `*args` and `**kwargs` in the following function:
3033    ///
3034    /// ```python
3035    /// def foo(*args, **kwargs): pass
3036    /// ```
3037    Variadic(&'a Parameter),
3038
3039    /// Non-variadic parameters can have default values,
3040    /// though they won't necessarily always have them:
3041    ///
3042    /// ```python
3043    /// def bar(a=1, /, b=2, *, c=3): pass
3044    /// ```
3045    NonVariadic(&'a ParameterWithDefault),
3046}
3047
3048impl<'a> AnyParameterRef<'a> {
3049    pub const fn as_parameter(self) -> &'a Parameter {
3050        match self {
3051            Self::NonVariadic(param) => &param.parameter,
3052            Self::Variadic(param) => param,
3053        }
3054    }
3055
3056    pub const fn name(self) -> &'a Identifier {
3057        &self.as_parameter().name
3058    }
3059
3060    pub const fn is_variadic(self) -> bool {
3061        matches!(self, Self::Variadic(_))
3062    }
3063
3064    pub fn annotation(self) -> Option<&'a Expr> {
3065        self.as_parameter().annotation.as_deref()
3066    }
3067
3068    pub fn default(self) -> Option<&'a Expr> {
3069        match self {
3070            Self::NonVariadic(param) => param.default.as_deref(),
3071            Self::Variadic(_) => None,
3072        }
3073    }
3074}
3075
3076impl Ranged for AnyParameterRef<'_> {
3077    fn range(&self) -> TextRange {
3078        match self {
3079            Self::NonVariadic(param) => param.range,
3080            Self::Variadic(param) => param.range,
3081        }
3082    }
3083}
3084
3085/// An alternative type of AST `arguments`. This is ruff_python_parser-friendly and human-friendly definition of function arguments.
3086/// This form also has advantage to implement pre-order traverse.
3087///
3088/// `defaults` and `kw_defaults` fields are removed and the default values are placed under each [`ParameterWithDefault`] typed argument.
3089/// `vararg` and `kwarg` are still typed as `arg` because they never can have a default value.
3090///
3091/// The original Python-style AST type orders `kwonlyargs` fields by default existence; [Parameters] has location-ordered `kwonlyargs` fields.
3092///
3093/// NOTE: This type differs from the original Python AST. See: [arguments](https://docs.python.org/3/library/ast.html#ast.arguments).
3094
3095#[derive(Clone, Debug, PartialEq, Default)]
3096#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
3097pub struct Parameters {
3098    pub range: TextRange,
3099    pub node_index: AtomicNodeIndex,
3100    pub posonlyargs: ThinVec<ParameterWithDefault>,
3101    pub args: ThinVec<ParameterWithDefault>,
3102    pub vararg: Option<Box<Parameter>>,
3103    pub kwonlyargs: ThinVec<ParameterWithDefault>,
3104    pub kwarg: Option<Box<Parameter>>,
3105}
3106
3107impl Parameters {
3108    /// Returns an iterator over all non-variadic parameters included in this [`Parameters`] node.
3109    ///
3110    /// The variadic parameters (`.vararg` and `.kwarg`) can never have default values;
3111    /// non-variadic parameters sometimes will.
3112    pub fn iter_non_variadic_params(&self) -> impl Iterator<Item = &ParameterWithDefault> {
3113        self.posonlyargs
3114            .iter()
3115            .chain(&self.args)
3116            .chain(&self.kwonlyargs)
3117    }
3118
3119    /// Returns the [`ParameterWithDefault`] with the given name, or `None` if no such [`ParameterWithDefault`] exists.
3120    pub fn find(&self, name: &str) -> Option<&ParameterWithDefault> {
3121        self.iter_non_variadic_params()
3122            .find(|arg| arg.parameter.name.as_str() == name)
3123    }
3124
3125    /// Returns the index of the parameter with the given name
3126    pub fn index(&self, name: &str) -> Option<usize> {
3127        self.iter_non_variadic_params()
3128            .position(|arg| arg.parameter.name.as_str() == name)
3129    }
3130
3131    /// Returns an iterator over all parameters included in this [`Parameters`] node.
3132    pub fn iter(&self) -> ParametersIterator<'_> {
3133        ParametersIterator::new(self)
3134    }
3135
3136    /// Returns the total number of parameters included in this [`Parameters`] node.
3137    pub fn len(&self) -> usize {
3138        let Parameters {
3139            range: _,
3140            node_index: _,
3141            posonlyargs,
3142            args,
3143            vararg,
3144            kwonlyargs,
3145            kwarg,
3146        } = self;
3147        // Safety: a Python function can have an arbitrary number of parameters,
3148        // so theoretically this could be a number that wouldn't fit into a usize,
3149        // which would lead to a panic. A Python function with that many parameters
3150        // is extremely unlikely outside of generated code, however, and it's even
3151        // more unlikely that we'd find a function with that many parameters in a
3152        // source-code file <=4GB large (Ruff's maximum).
3153        posonlyargs
3154            .len()
3155            .checked_add(args.len())
3156            .and_then(|length| length.checked_add(usize::from(vararg.is_some())))
3157            .and_then(|length| length.checked_add(kwonlyargs.len()))
3158            .and_then(|length| length.checked_add(usize::from(kwarg.is_some())))
3159            .expect("Failed to fit the number of parameters into a usize")
3160    }
3161
3162    /// Returns `true` if a parameter with the given name is included in this [`Parameters`].
3163    pub fn includes(&self, name: &str) -> bool {
3164        self.iter().any(|param| param.name() == name)
3165    }
3166
3167    /// Returns `true` if the [`Parameters`] is empty.
3168    pub fn is_empty(&self) -> bool {
3169        self.posonlyargs.is_empty()
3170            && self.args.is_empty()
3171            && self.kwonlyargs.is_empty()
3172            && self.vararg.is_none()
3173            && self.kwarg.is_none()
3174    }
3175
3176    /// Returns an iterator over all parameters in source order.
3177    ///
3178    /// This differs from [`Parameters::iter`] which returns parameters
3179    /// in type-based order (positional-only, regular, variadic, keyword-only,
3180    /// keyword). For well-formed Python the two orderings are identical, but
3181    /// error recovery can produce ASTs where variadic parameters appear before
3182    /// non-variadic ones (e.g. `def foo(**kwargs, a):`).
3183    pub fn iter_source_order(&self) -> ParametersSourceOrderIterator<'_> {
3184        let mut variadics = [self.vararg.as_deref(), self.kwarg.as_deref()];
3185        variadics.sort_by_key(|param| param.map_or(TextSize::new(u32::MAX), Ranged::start));
3186
3187        ParametersSourceOrderIterator {
3188            next_non_variadic_peeked: None,
3189            posonlyargs: self.posonlyargs.iter(),
3190            args: self.args.iter(),
3191            kwonlyargs: self.kwonlyargs.iter(),
3192            variadics,
3193            next_variadic: 0,
3194        }
3195    }
3196}
3197
3198pub struct ParametersIterator<'a> {
3199    posonlyargs: Iter<'a, ParameterWithDefault>,
3200    args: Iter<'a, ParameterWithDefault>,
3201    vararg: Option<&'a Parameter>,
3202    kwonlyargs: Iter<'a, ParameterWithDefault>,
3203    kwarg: Option<&'a Parameter>,
3204}
3205
3206impl<'a> ParametersIterator<'a> {
3207    fn new(parameters: &'a Parameters) -> Self {
3208        let Parameters {
3209            range: _,
3210            node_index: _,
3211            posonlyargs,
3212            args,
3213            vararg,
3214            kwonlyargs,
3215            kwarg,
3216        } = parameters;
3217        Self {
3218            posonlyargs: posonlyargs.iter(),
3219            args: args.iter(),
3220            vararg: vararg.as_deref(),
3221            kwonlyargs: kwonlyargs.iter(),
3222            kwarg: kwarg.as_deref(),
3223        }
3224    }
3225}
3226
3227impl<'a> Iterator for ParametersIterator<'a> {
3228    type Item = AnyParameterRef<'a>;
3229
3230    fn next(&mut self) -> Option<Self::Item> {
3231        let ParametersIterator {
3232            posonlyargs,
3233            args,
3234            vararg,
3235            kwonlyargs,
3236            kwarg,
3237        } = self;
3238
3239        if let Some(param) = posonlyargs.next() {
3240            return Some(AnyParameterRef::NonVariadic(param));
3241        }
3242        if let Some(param) = args.next() {
3243            return Some(AnyParameterRef::NonVariadic(param));
3244        }
3245        if let Some(param) = vararg.take() {
3246            return Some(AnyParameterRef::Variadic(param));
3247        }
3248        if let Some(param) = kwonlyargs.next() {
3249            return Some(AnyParameterRef::NonVariadic(param));
3250        }
3251        kwarg.take().map(AnyParameterRef::Variadic)
3252    }
3253
3254    fn size_hint(&self) -> (usize, Option<usize>) {
3255        let ParametersIterator {
3256            posonlyargs,
3257            args,
3258            vararg,
3259            kwonlyargs,
3260            kwarg,
3261        } = self;
3262
3263        let posonlyargs_len = posonlyargs.len();
3264        let args_len = args.len();
3265        let vararg_len = usize::from(vararg.is_some());
3266        let kwonlyargs_len = kwonlyargs.len();
3267        let kwarg_len = usize::from(kwarg.is_some());
3268
3269        let lower = posonlyargs_len
3270            .saturating_add(args_len)
3271            .saturating_add(vararg_len)
3272            .saturating_add(kwonlyargs_len)
3273            .saturating_add(kwarg_len);
3274
3275        let upper = posonlyargs_len
3276            .checked_add(args_len)
3277            .and_then(|length| length.checked_add(vararg_len))
3278            .and_then(|length| length.checked_add(kwonlyargs_len))
3279            .and_then(|length| length.checked_add(kwarg_len));
3280
3281        (lower, upper)
3282    }
3283
3284    fn last(mut self) -> Option<Self::Item> {
3285        self.next_back()
3286    }
3287}
3288
3289impl DoubleEndedIterator for ParametersIterator<'_> {
3290    fn next_back(&mut self) -> Option<Self::Item> {
3291        let ParametersIterator {
3292            posonlyargs,
3293            args,
3294            vararg,
3295            kwonlyargs,
3296            kwarg,
3297        } = self;
3298
3299        if let Some(param) = kwarg.take() {
3300            return Some(AnyParameterRef::Variadic(param));
3301        }
3302        if let Some(param) = kwonlyargs.next_back() {
3303            return Some(AnyParameterRef::NonVariadic(param));
3304        }
3305        if let Some(param) = vararg.take() {
3306            return Some(AnyParameterRef::Variadic(param));
3307        }
3308        if let Some(param) = args.next_back() {
3309            return Some(AnyParameterRef::NonVariadic(param));
3310        }
3311        posonlyargs.next_back().map(AnyParameterRef::NonVariadic)
3312    }
3313}
3314
3315impl FusedIterator for ParametersIterator<'_> {}
3316
3317/// We rely on the same invariants outlined in the comment above `Parameters::len()`
3318/// in order to implement `ExactSizeIterator` here
3319impl ExactSizeIterator for ParametersIterator<'_> {}
3320
3321impl<'a> IntoIterator for &'a Parameters {
3322    type IntoIter = ParametersIterator<'a>;
3323    type Item = AnyParameterRef<'a>;
3324    fn into_iter(self) -> Self::IntoIter {
3325        self.iter()
3326    }
3327}
3328
3329impl<'a> IntoIterator for &'a Box<Parameters> {
3330    type IntoIter = ParametersIterator<'a>;
3331    type Item = AnyParameterRef<'a>;
3332    fn into_iter(self) -> Self::IntoIter {
3333        (&**self).into_iter()
3334    }
3335}
3336
3337/// The iterator returned by [`Parameters::iter_source_order`].
3338pub struct ParametersSourceOrderIterator<'a> {
3339    next_non_variadic_peeked: Option<&'a ParameterWithDefault>,
3340    posonlyargs: Iter<'a, ParameterWithDefault>,
3341    args: Iter<'a, ParameterWithDefault>,
3342    kwonlyargs: Iter<'a, ParameterWithDefault>,
3343    variadics: [Option<&'a Parameter>; 2],
3344    next_variadic: usize,
3345}
3346
3347impl<'a> ParametersSourceOrderIterator<'a> {
3348    /// Returns the next variadic parameter that appears before `before`, if any.
3349    fn next_variadic_before(&mut self, before: TextSize) -> Option<&'a Parameter> {
3350        let param = self.variadics.get(self.next_variadic).copied().flatten()?;
3351        if param.start() < before {
3352            self.next_variadic += 1;
3353            Some(param)
3354        } else {
3355            None
3356        }
3357    }
3358
3359    fn next_non_variadic(&mut self) -> Option<&'a ParameterWithDefault> {
3360        self.next_non_variadic_peeked
3361            .take()
3362            .or_else(|| self.posonlyargs.next())
3363            .or_else(|| self.args.next())
3364            .or_else(|| self.kwonlyargs.next())
3365    }
3366
3367    fn peek_next_non_variadic(&mut self) -> Option<&'a ParameterWithDefault> {
3368        let next = self.next_non_variadic()?;
3369        self.next_non_variadic_peeked = Some(next);
3370        Some(next)
3371    }
3372}
3373
3374impl<'a> Iterator for ParametersSourceOrderIterator<'a> {
3375    type Item = AnyParameterRef<'a>;
3376
3377    fn next(&mut self) -> Option<Self::Item> {
3378        // If there's a variadic parameter that comes before the next
3379        // non-variadic parameter, emit it first.
3380        let next_non_variadic_start = self
3381            .peek_next_non_variadic()
3382            .map_or(TextSize::new(u32::MAX), Ranged::start);
3383
3384        if let Some(variadic) = self.next_variadic_before(next_non_variadic_start) {
3385            return Some(AnyParameterRef::Variadic(variadic));
3386        }
3387
3388        if let Some(non_variadic) = self.next_non_variadic() {
3389            return Some(AnyParameterRef::NonVariadic(non_variadic));
3390        }
3391
3392        // Drain remaining variadics.
3393        self.next_variadic_before(TextSize::new(u32::MAX))
3394            .map(AnyParameterRef::Variadic)
3395    }
3396}
3397
3398impl FusedIterator for ParametersSourceOrderIterator<'_> {}
3399
3400/// An alternative type of AST `arg`. This is used for each function argument that might have a default value.
3401/// Used by `Arguments` original type.
3402///
3403/// NOTE: This type is different from original Python AST.
3404#[derive(Clone, Debug, PartialEq)]
3405#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
3406pub struct ParameterWithDefault {
3407    pub range: TextRange,
3408    pub node_index: AtomicNodeIndex,
3409    pub parameter: Parameter,
3410    pub default: Option<Box<Expr>>,
3411}
3412
3413impl ParameterWithDefault {
3414    pub fn default(&self) -> Option<&Expr> {
3415        self.default.as_deref()
3416    }
3417
3418    pub const fn name(&self) -> &Identifier {
3419        self.parameter.name()
3420    }
3421
3422    pub fn annotation(&self) -> Option<&Expr> {
3423        self.parameter.annotation()
3424    }
3425
3426    /// Return `true` if the parameter name uses the pre-PEP-570 convention
3427    /// (specified in PEP 484) to indicate to a type checker that it should be treated
3428    /// as positional-only.
3429    pub fn uses_pep_484_positional_only_convention(&self) -> bool {
3430        let name = self.name();
3431        name.starts_with("__") && !name.ends_with("__")
3432    }
3433}
3434
3435/// An AST node used to represent the arguments passed to a function call or class definition.
3436///
3437/// For example, given:
3438/// ```python
3439/// foo(1, 2, 3, bar=4, baz=5)
3440/// ```
3441/// The `Arguments` node would span from the left to right parentheses (inclusive), and contain
3442/// the arguments and keyword arguments in the order they appear in the source code.
3443///
3444/// Similarly, given:
3445/// ```python
3446/// class Foo(Bar, baz=1, qux=2):
3447///     pass
3448/// ```
3449/// The `Arguments` node would again span from the left to right parentheses (inclusive), and
3450/// contain the `Bar` argument and the `baz` and `qux` keyword arguments in the order they
3451/// appear in the source code.
3452///
3453/// In the context of a class definition, the Python-style AST refers to the arguments as `bases`,
3454/// as they represent the "explicitly specified base classes", while the keyword arguments are
3455/// typically used for `metaclass`, with any additional arguments being passed to the `metaclass`.
3456
3457#[derive(Clone, Debug, PartialEq)]
3458#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
3459pub struct Arguments {
3460    pub range: TextRange,
3461    pub node_index: AtomicNodeIndex,
3462    pub args: Box<[Expr]>,
3463    pub keywords: ThinVec<Keyword>,
3464}
3465
3466/// An entry in the argument list of a function call.
3467#[derive(Copy, Clone, Debug, PartialEq)]
3468pub enum ArgOrKeyword<'a> {
3469    Arg(&'a Expr),
3470    Keyword(&'a Keyword),
3471}
3472
3473impl<'a> ArgOrKeyword<'a> {
3474    pub const fn value(self) -> &'a Expr {
3475        match self {
3476            ArgOrKeyword::Arg(argument) => argument,
3477            ArgOrKeyword::Keyword(keyword) => &keyword.value,
3478        }
3479    }
3480
3481    pub const fn is_variadic(self) -> bool {
3482        match self {
3483            ArgOrKeyword::Arg(expr) => expr.is_starred_expr(),
3484            ArgOrKeyword::Keyword(keyword) => keyword.arg.is_none(),
3485        }
3486    }
3487
3488    pub const fn as_variadic(self) -> Option<&'a Keyword> {
3489        match self {
3490            ArgOrKeyword::Keyword(keyword) if keyword.arg.is_none() => Some(keyword),
3491            _ => None,
3492        }
3493    }
3494
3495    pub const fn as_keyword(self) -> Option<&'a Keyword> {
3496        match self {
3497            ArgOrKeyword::Keyword(keyword) => Some(keyword),
3498            ArgOrKeyword::Arg(_) => None,
3499        }
3500    }
3501}
3502
3503impl<'a> From<&'a Expr> for ArgOrKeyword<'a> {
3504    fn from(arg: &'a Expr) -> Self {
3505        Self::Arg(arg)
3506    }
3507}
3508
3509impl<'a> From<&'a Keyword> for ArgOrKeyword<'a> {
3510    fn from(keyword: &'a Keyword) -> Self {
3511        Self::Keyword(keyword)
3512    }
3513}
3514
3515impl Ranged for ArgOrKeyword<'_> {
3516    fn range(&self) -> TextRange {
3517        match self {
3518            Self::Arg(arg) => arg.range(),
3519            Self::Keyword(keyword) => keyword.range(),
3520        }
3521    }
3522}
3523
3524impl Arguments {
3525    /// Return the number of positional and keyword arguments.
3526    pub fn len(&self) -> usize {
3527        self.args.len() + self.keywords.len()
3528    }
3529
3530    /// Return `true` if there are no positional or keyword arguments.
3531    pub fn is_empty(&self) -> bool {
3532        self.len() == 0
3533    }
3534
3535    /// Return the [`Keyword`] with the given name, or `None` if no such [`Keyword`] exists.
3536    pub fn find_keyword(&self, keyword_name: &str) -> Option<&Keyword> {
3537        self.keywords.iter().find(|keyword| {
3538            let Keyword { arg, .. } = keyword;
3539            arg.as_ref().is_some_and(|arg| arg == keyword_name)
3540        })
3541    }
3542
3543    /// Return the positional argument at the given index, or `None` if no such argument exists.
3544    pub fn find_positional(&self, position: usize) -> Option<&Expr> {
3545        self.args
3546            .iter()
3547            .take_while(|expr| !expr.is_starred_expr())
3548            .nth(position)
3549    }
3550
3551    /// Return the value for the argument with the given name or at the given position, or `None` if no such
3552    /// argument exists. Used to retrieve argument values that can be provided _either_ as keyword or
3553    /// positional arguments.
3554    pub fn find_argument_value(&self, name: &str, position: usize) -> Option<&Expr> {
3555        self.find_argument(name, position).map(ArgOrKeyword::value)
3556    }
3557
3558    /// Return the argument with the given name or at the given position, or `None` if no such
3559    /// argument exists. Used to retrieve arguments that can be provided _either_ as keyword or
3560    /// positional arguments.
3561    pub fn find_argument(&self, name: &str, position: usize) -> Option<ArgOrKeyword<'_>> {
3562        self.find_keyword(name)
3563            .map(ArgOrKeyword::from)
3564            .or_else(|| self.find_positional(position).map(ArgOrKeyword::from))
3565    }
3566
3567    /// Iterates over the positional and keyword arguments in the order of declaration.
3568    ///
3569    /// Positional arguments are generally before keyword arguments, but star arguments are an
3570    /// exception:
3571    /// ```python
3572    /// class A(*args, a=2, *args2, **kwargs):
3573    ///     pass
3574    ///
3575    /// f(*args, a=2, *args2, **kwargs)
3576    /// ```
3577    /// where `*args` and `args2` are `args` while `a=1` and `kwargs` are `keywords`.
3578    ///
3579    /// If you would just chain `args` and `keywords` the call would get reordered which we don't
3580    /// want. This function instead "merge sorts" them into the correct order.
3581    ///
3582    /// Note that the order of evaluation is always first `args`, then `keywords`:
3583    /// ```python
3584    /// def f(*args, **kwargs):
3585    ///     pass
3586    ///
3587    /// def g(x):
3588    ///     print(x)
3589    ///     return x
3590    ///
3591    ///
3592    /// f(*g([1]), a=g(2), *g([3]), **g({"4": 5}))
3593    /// ```
3594    /// Output:
3595    /// ```text
3596    /// [1]
3597    /// [3]
3598    /// 2
3599    /// {'4': 5}
3600    /// ```
3601    pub fn iter_source_order(&self) -> ArgumentsSourceOrder<'_> {
3602        ArgumentsSourceOrder {
3603            args: &self.args,
3604            keywords: &self.keywords,
3605            next_arg: 0,
3606            next_keyword: 0,
3607        }
3608    }
3609
3610    pub fn inner_range(&self) -> TextRange {
3611        TextRange::new(self.l_paren_range().end(), self.r_paren_range().start())
3612    }
3613
3614    pub fn l_paren_range(&self) -> TextRange {
3615        TextRange::at(self.start(), '('.text_len())
3616    }
3617
3618    pub fn r_paren_range(&self) -> TextRange {
3619        TextRange::new(self.end() - ')'.text_len(), self.end())
3620    }
3621}
3622
3623/// The iterator returned by [`Arguments::iter_source_order`].
3624#[derive(Clone)]
3625pub struct ArgumentsSourceOrder<'a> {
3626    args: &'a [Expr],
3627    keywords: &'a [Keyword],
3628    next_arg: usize,
3629    next_keyword: usize,
3630}
3631
3632impl<'a> Iterator for ArgumentsSourceOrder<'a> {
3633    type Item = ArgOrKeyword<'a>;
3634
3635    fn next(&mut self) -> Option<Self::Item> {
3636        let arg = self.args.get(self.next_arg);
3637        let keyword = self.keywords.get(self.next_keyword);
3638
3639        if let Some(arg) = arg
3640            && keyword.is_none_or(|keyword| arg.start() <= keyword.start())
3641        {
3642            self.next_arg += 1;
3643            Some(ArgOrKeyword::Arg(arg))
3644        } else if let Some(keyword) = keyword {
3645            self.next_keyword += 1;
3646            Some(ArgOrKeyword::Keyword(keyword))
3647        } else {
3648            None
3649        }
3650    }
3651}
3652
3653impl FusedIterator for ArgumentsSourceOrder<'_> {}
3654
3655/// An AST node used to represent a sequence of type parameters.
3656///
3657/// For example, given:
3658/// ```python
3659/// class C[T, U, V]: ...
3660/// ```
3661/// The `TypeParams` node would span from the left to right brackets (inclusive), and contain
3662/// the `T`, `U`, and `V` type parameters in the order they appear in the source code.
3663
3664#[derive(Clone, Debug, PartialEq)]
3665#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
3666pub struct TypeParams {
3667    pub range: TextRange,
3668    pub node_index: AtomicNodeIndex,
3669    pub type_params: Vec<TypeParam>,
3670}
3671
3672impl Deref for TypeParams {
3673    type Target = [TypeParam];
3674
3675    fn deref(&self) -> &Self::Target {
3676        &self.type_params
3677    }
3678}
3679
3680impl<'a> IntoIterator for &'a TypeParams {
3681    type Item = &'a TypeParam;
3682    type IntoIter = std::slice::Iter<'a, TypeParam>;
3683
3684    fn into_iter(self) -> Self::IntoIter {
3685        self.type_params.iter()
3686    }
3687}
3688
3689/// A suite represents a sequence of [`Stmt`].
3690///
3691/// See: <https://docs.python.org/3/reference/compound_stmts.html#grammar-token-python-grammar-suite>
3692pub type Suite = ThinVec<Stmt>;
3693
3694pub type DecoratorList = ThinVec<Decorator>;
3695
3696pub type Patterns = ThinVec<Pattern>;
3697
3698pub type PatternKeys = ThinVec<Expr>;
3699
3700pub type ParameterWithDefaults = ThinVec<ParameterWithDefault>;
3701
3702/// The kind of escape command as defined in [IPython Syntax] in the IPython codebase.
3703///
3704/// [IPython Syntax]: https://github.com/ipython/ipython/blob/635815e8f1ded5b764d66cacc80bbe25e9e2587f/IPython/core/inputtransformer2.py#L335-L343
3705#[derive(PartialEq, Eq, Debug, Clone, Hash, Copy)]
3706#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
3707pub enum IpyEscapeKind {
3708    /// Send line to underlying system shell (`!`).
3709    Shell,
3710    /// Send line to system shell and capture output (`!!`).
3711    ShCap,
3712    /// Show help on object (`?`).
3713    Help,
3714    /// Show help on object, with extra verbosity (`??`).
3715    Help2,
3716    /// Call magic function (`%`).
3717    Magic,
3718    /// Call cell magic function (`%%`).
3719    Magic2,
3720    /// Call first argument with rest of line as arguments after splitting on whitespace
3721    /// and quote each as string (`,`).
3722    Quote,
3723    /// Call first argument with rest of line as an argument quoted as a single string (`;`).
3724    Quote2,
3725    /// Call first argument with rest of line as arguments (`/`).
3726    Paren,
3727}
3728
3729impl TryFrom<char> for IpyEscapeKind {
3730    type Error = String;
3731
3732    fn try_from(ch: char) -> Result<Self, Self::Error> {
3733        match ch {
3734            '!' => Ok(IpyEscapeKind::Shell),
3735            '?' => Ok(IpyEscapeKind::Help),
3736            '%' => Ok(IpyEscapeKind::Magic),
3737            ',' => Ok(IpyEscapeKind::Quote),
3738            ';' => Ok(IpyEscapeKind::Quote2),
3739            '/' => Ok(IpyEscapeKind::Paren),
3740            _ => Err(format!("Unexpected magic escape: {ch}")),
3741        }
3742    }
3743}
3744
3745impl TryFrom<[char; 2]> for IpyEscapeKind {
3746    type Error = String;
3747
3748    fn try_from(ch: [char; 2]) -> Result<Self, Self::Error> {
3749        match ch {
3750            ['!', '!'] => Ok(IpyEscapeKind::ShCap),
3751            ['?', '?'] => Ok(IpyEscapeKind::Help2),
3752            ['%', '%'] => Ok(IpyEscapeKind::Magic2),
3753            [c1, c2] => Err(format!("Unexpected magic escape: {c1}{c2}")),
3754        }
3755    }
3756}
3757
3758impl fmt::Display for IpyEscapeKind {
3759    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3760        f.write_str(self.as_str())
3761    }
3762}
3763
3764impl IpyEscapeKind {
3765    /// Returns `true` if the escape kind is help i.e., `?` or `??`.
3766    pub const fn is_help(self) -> bool {
3767        matches!(self, IpyEscapeKind::Help | IpyEscapeKind::Help2)
3768    }
3769
3770    /// Returns `true` if the escape kind is magic i.e., `%` or `%%`.
3771    pub const fn is_magic(self) -> bool {
3772        matches!(self, IpyEscapeKind::Magic | IpyEscapeKind::Magic2)
3773    }
3774
3775    pub fn as_str(self) -> &'static str {
3776        match self {
3777            IpyEscapeKind::Shell => "!",
3778            IpyEscapeKind::ShCap => "!!",
3779            IpyEscapeKind::Help => "?",
3780            IpyEscapeKind::Help2 => "??",
3781            IpyEscapeKind::Magic => "%",
3782            IpyEscapeKind::Magic2 => "%%",
3783            IpyEscapeKind::Quote => ",",
3784            IpyEscapeKind::Quote2 => ";",
3785            IpyEscapeKind::Paren => "/",
3786        }
3787    }
3788}
3789
3790/// An `Identifier` with an empty `id` is invalid.
3791///
3792/// For example, in the following code `id` will be empty.
3793/// ```python
3794/// def 1():
3795///     ...
3796/// ```
3797#[derive(Clone, Debug, PartialEq, Eq, Hash)]
3798#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
3799pub struct Identifier {
3800    pub id: Name,
3801    pub range: TextRange,
3802    pub node_index: AtomicNodeIndex,
3803}
3804
3805impl Identifier {
3806    #[inline]
3807    pub fn new(id: impl Into<Name>, range: TextRange) -> Self {
3808        Self {
3809            id: id.into(),
3810            node_index: AtomicNodeIndex::NONE,
3811            range,
3812        }
3813    }
3814
3815    pub fn id(&self) -> &Name {
3816        &self.id
3817    }
3818
3819    pub fn is_valid(&self) -> bool {
3820        !self.id.is_empty()
3821    }
3822}
3823
3824impl Identifier {
3825    #[inline]
3826    pub fn as_str(&self) -> &str {
3827        self.id.as_str()
3828    }
3829}
3830
3831impl PartialEq<str> for Identifier {
3832    #[inline]
3833    fn eq(&self, other: &str) -> bool {
3834        self.id == other
3835    }
3836}
3837
3838impl PartialEq<String> for Identifier {
3839    #[inline]
3840    fn eq(&self, other: &String) -> bool {
3841        self.id == other
3842    }
3843}
3844
3845impl std::ops::Deref for Identifier {
3846    type Target = str;
3847    #[inline]
3848    fn deref(&self) -> &Self::Target {
3849        self.id.as_str()
3850    }
3851}
3852
3853impl AsRef<str> for Identifier {
3854    #[inline]
3855    fn as_ref(&self) -> &str {
3856        self.id.as_str()
3857    }
3858}
3859
3860impl std::fmt::Display for Identifier {
3861    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3862        std::fmt::Display::fmt(&self.id, f)
3863    }
3864}
3865
3866impl From<Identifier> for Name {
3867    #[inline]
3868    fn from(identifier: Identifier) -> Name {
3869        identifier.id
3870    }
3871}
3872
3873#[derive(Clone, Copy, Debug, Hash, PartialEq)]
3874#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
3875pub enum Singleton {
3876    None,
3877    True,
3878    False,
3879}
3880
3881impl From<bool> for Singleton {
3882    fn from(value: bool) -> Self {
3883        if value {
3884            Singleton::True
3885        } else {
3886            Singleton::False
3887        }
3888    }
3889}
3890
3891#[cfg(test)]
3892mod tests {
3893    use crate::generated::*;
3894    use crate::{Arguments, Mod, Parameters};
3895
3896    #[test]
3897    #[cfg(target_pointer_width = "64")]
3898    fn size() {
3899        assert_eq!(std::mem::size_of::<Stmt>(), 96);
3900        assert_eq!(std::mem::size_of::<StmtFunctionDef>(), 96);
3901        assert_eq!(std::mem::size_of::<StmtClassDef>(), 88);
3902        assert_eq!(std::mem::size_of::<StmtTry>(), 64);
3903        assert_eq!(std::mem::size_of::<Mod>(), 32);
3904        assert_eq!(std::mem::size_of::<Pattern>(), 80);
3905        assert_eq!(std::mem::size_of::<Parameters>(), 56);
3906        assert_eq!(std::mem::size_of::<Arguments>(), 40);
3907        assert_eq!(std::mem::size_of::<Expr>(), 72);
3908        assert_eq!(std::mem::size_of::<ExprAttribute>(), 64);
3909        assert_eq!(std::mem::size_of::<ExprAwait>(), 24);
3910        assert_eq!(std::mem::size_of::<ExprBinOp>(), 32);
3911        assert_eq!(std::mem::size_of::<ExprBoolOp>(), 40);
3912        assert_eq!(std::mem::size_of::<ExprBooleanLiteral>(), 16);
3913        assert_eq!(std::mem::size_of::<ExprBytesLiteral>(), 48);
3914        assert_eq!(std::mem::size_of::<ExprCall>(), 64);
3915        assert_eq!(std::mem::size_of::<ExprCompare>(), 56);
3916        assert_eq!(std::mem::size_of::<ExprDict>(), 40);
3917        assert_eq!(std::mem::size_of::<ExprDictComp>(), 56);
3918        assert_eq!(std::mem::size_of::<ExprEllipsisLiteral>(), 12);
3919        assert_eq!(std::mem::size_of::<ExprFString>(), 56);
3920        assert_eq!(std::mem::size_of::<ExprGenerator>(), 48);
3921        assert_eq!(std::mem::size_of::<ExprIf>(), 40);
3922        assert_eq!(std::mem::size_of::<ExprIpyEscapeCommand>(), 32);
3923        assert_eq!(std::mem::size_of::<ExprLambda>(), 32);
3924        assert_eq!(std::mem::size_of::<ExprList>(), 40);
3925        assert_eq!(std::mem::size_of::<ExprListComp>(), 48);
3926        assert_eq!(std::mem::size_of::<ExprName>(), 40);
3927        assert_eq!(std::mem::size_of::<ExprNamed>(), 32);
3928        assert_eq!(std::mem::size_of::<ExprNoneLiteral>(), 12);
3929        assert_eq!(std::mem::size_of::<ExprNumberLiteral>(), 40);
3930        assert_eq!(std::mem::size_of::<ExprSet>(), 40);
3931        assert_eq!(std::mem::size_of::<ExprSetComp>(), 48);
3932        assert_eq!(std::mem::size_of::<ExprSlice>(), 40);
3933        assert_eq!(std::mem::size_of::<ExprStarred>(), 24);
3934        assert_eq!(std::mem::size_of::<ExprStringLiteral>(), 64);
3935        assert_eq!(std::mem::size_of::<ExprSubscript>(), 32);
3936        assert_eq!(std::mem::size_of::<ExprTuple>(), 40);
3937        assert_eq!(std::mem::size_of::<ExprUnaryOp>(), 24);
3938        assert_eq!(std::mem::size_of::<ExprYield>(), 24);
3939        assert_eq!(std::mem::size_of::<ExprYieldFrom>(), 24);
3940    }
3941}