1#![allow(clippy::derive_partial_eq_without_eq)]
2
3use crate::AtomicNodeIndex;
4use crate::generated::{
5 ExprBytesLiteral, ExprCall, ExprDict, ExprFString, ExprList, ExprName, ExprSet,
6 ExprStringLiteral, ExprTString, ExprTuple, PatternMatchAs, PatternMatchOr, StmtClassDef,
7};
8use std::borrow::Cow;
9use std::fmt;
10use std::fmt::Debug;
11use std::iter::FusedIterator;
12use std::ops::{Deref, DerefMut};
13use std::slice::{Iter, IterMut};
14use std::sync::OnceLock;
15
16use bitflags::bitflags;
17use thin_vec::ThinVec;
18
19use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
20
21use crate::str_prefix::{
22 AnyStringPrefix, ByteStringPrefix, FStringPrefix, StringLiteralPrefix, TStringPrefix,
23};
24use crate::{
25 Expr, ExprRef, InterpolatedStringElement, LiteralExpressionRef, OperatorPrecedence, Pattern,
26 Stmt, TypeParam, int,
27 name::Name,
28 str::{Quote, TripleQuotes},
29};
30
31impl StmtClassDef {
32 pub fn bases(&self) -> &[Expr] {
34 match &self.arguments {
35 Some(arguments) => &arguments.args,
36 None => &[],
37 }
38 }
39
40 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 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 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 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 pub fn precedence(&self) -> OperatorPrecedence {
101 OperatorPrecedence::from(self)
102 }
103}
104
105impl ExprRef<'_> {
106 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#[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 pub fn iter_keys(&self) -> DictKeyIterator<'_> {
177 DictKeyIterator::new(&self.items)
178 }
179
180 pub fn iter_values(&self) -> DictValueIterator<'_> {
183 DictValueIterator::new(&self.items)
184 }
185
186 pub fn key(&self, n: usize) -> Option<&Expr> {
191 self.items[n].key()
192 }
193
194 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#[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#[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#[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 None = -1, Str = b's' as i8,
384 Ascii = b'a' as i8,
386 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#[derive(Clone, PartialEq, Eq, Hash)]
411#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
412pub struct DebugText {
413 text: compact_str::CompactString,
415 expression_start: u32,
417 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 pub fn as_str(&self) -> &str {
450 &self.text
451 }
452
453 pub fn leading(&self) -> &str {
455 &self.text[..self.expression_start as usize]
456 }
457
458 pub fn expression(&self) -> &str {
460 &self.text[self.expression_start as usize..self.expression_end as usize]
461 }
462
463 pub fn trailing(&self) -> &str {
465 &self.text[self.expression_end as usize..]
466 }
467}
468
469impl ExprFString {
470 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#[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 pub fn single(value: FString) -> Self {
490 Self {
491 inner: FStringValueInner::Single(FStringPart::FString(value)),
492 }
493 }
494
495 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 pub fn is_implicit_concatenated(&self) -> bool {
514 matches!(self.inner, FStringValueInner::Concatenated(_))
515 }
516
517 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 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 pub fn iter(&self) -> Iter<'_, FStringPart> {
535 self.as_slice().iter()
536 }
537
538 pub fn iter_mut(&mut self) -> IterMut<'_, FStringPart> {
541 self.as_mut_slice().iter_mut()
542 }
543
544 pub fn literals(&self) -> impl Iterator<Item = &StringLiteral> {
554 self.iter().filter_map(|part| part.as_literal())
555 }
556
557 pub fn f_strings(&self) -> impl Iterator<Item = &FString> {
567 self.iter().filter_map(|part| part.as_f_string())
568 }
569
570 pub fn elements(&self) -> impl Iterator<Item = &InterpolatedStringElement> {
582 self.f_strings().flat_map(|fstring| fstring.elements.iter())
583 }
584
585 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#[derive(Clone, Debug, PartialEq)]
619#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
620enum FStringValueInner {
621 Single(FStringPart),
626
627 Concatenated(Vec<FStringPart>),
629}
630
631#[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 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#[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 pub fn single(value: TString) -> Self {
685 Self {
686 inner: TStringValueInner::Single(value),
687 }
688 }
689
690 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 pub fn is_implicit_concatenated(&self) -> bool {
709 matches!(self.inner, TStringValueInner::Concatenated(_))
710 }
711
712 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 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 pub fn iter(&self) -> Iter<'_, TString> {
730 self.as_slice().iter()
731 }
732
733 pub fn iter_mut(&mut self) -> IterMut<'_, TString> {
736 self.as_mut_slice().iter_mut()
737 }
738
739 pub fn elements(&self) -> impl Iterator<Item = &InterpolatedStringElement> {
751 self.iter().flat_map(|tstring| tstring.elements.iter())
752 }
753
754 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#[derive(Clone, Debug, PartialEq)]
790#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
791enum TStringValueInner {
792 Single(TString),
794
795 Concatenated(Vec<TString>),
797}
798
799pub trait StringFlags: Copy {
800 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 fn is_triple_quoted(self) -> bool {
812 self.triple_quotes().is_yes()
813 }
814
815 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 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 fn opener_len(self) -> TextSize {
841 self.prefix().text_len() + self.quote_len()
842 }
843
844 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 const DOUBLE = 1 << 0;
892
893 const TRIPLE_QUOTED = 1 << 1;
897
898 const R_PREFIX_LOWER = 1 << 2;
901
902 const R_PREFIX_UPPER = 1 << 3;
908
909 const UNCLOSED = 1 << 4;
912 }
913}
914
915#[cfg(feature = "get-size")]
916impl get_size2::GetSize for InterpolatedStringFlagsInner {}
917
918#[derive(Copy, Clone, Eq, PartialEq, Hash)]
935#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
936pub struct FStringFlags(InterpolatedStringFlagsInner);
937
938impl FStringFlags {
939 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#[derive(Copy, Clone, Eq, PartialEq, Hash)]
1038#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1039pub struct TStringFlags(InterpolatedStringFlagsInner);
1040
1041impl TStringFlags {
1042 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 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 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 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 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#[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#[derive(Clone, Default, PartialEq)]
1230#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1231pub struct InterpolatedStringElements(Vec<InterpolatedStringElement>);
1232
1233impl InterpolatedStringElements {
1234 pub fn literals(&self) -> impl Iterator<Item = &InterpolatedStringLiteralElement> {
1236 self.iter().filter_map(|element| element.as_literal())
1237 }
1238
1239 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#[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 pub fn as_single_part_string(&self) -> Option<&StringLiteral> {
1324 match &self.value.inner {
1325 StringLiteralValueInner::Single(value) => Some(value),
1326 StringLiteralValueInner::Concatenated(_) => None,
1327 }
1328 }
1329}
1330
1331impl Ranged for ExprCall {
1332 fn range(&self) -> TextRange {
1333 TextRange::new(self.range_start, self.arguments.end())
1334 }
1335}
1336
1337#[expect(
1338 clippy::missing_fields_in_debug,
1339 reason = "`range_start` is represented by the reconstructed `range` field"
1340)]
1341impl fmt::Debug for ExprCall {
1342 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1343 formatter
1344 .debug_struct("ExprCall")
1345 .field("node_index", &self.node_index)
1346 .field("range", &self.range())
1347 .field("func", &self.func)
1348 .field("arguments", &self.arguments)
1349 .finish()
1350 }
1351}
1352
1353#[derive(Clone, Debug, PartialEq)]
1355#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1356pub struct StringLiteralValue {
1357 inner: StringLiteralValueInner,
1358}
1359
1360impl StringLiteralValue {
1361 pub fn single(string: StringLiteral) -> Self {
1363 Self {
1364 inner: StringLiteralValueInner::Single(string),
1365 }
1366 }
1367
1368 pub fn first_literal_flags(&self) -> StringLiteralFlags {
1372 self.iter()
1373 .next()
1374 .expect(
1375 "There should always be at least one string literal in an `ExprStringLiteral` node",
1376 )
1377 .flags
1378 }
1379
1380 pub fn concatenated(strings: Vec<StringLiteral>) -> Self {
1388 assert!(
1389 strings.len() > 1,
1390 "Use `StringLiteralValue::single` to create single-part strings"
1391 );
1392 Self {
1393 inner: StringLiteralValueInner::Concatenated(Box::new(ConcatenatedStringLiteral {
1394 strings,
1395 value: OnceLock::new(),
1396 })),
1397 }
1398 }
1399
1400 pub const fn is_implicit_concatenated(&self) -> bool {
1402 matches!(self.inner, StringLiteralValueInner::Concatenated(_))
1403 }
1404
1405 pub fn is_unicode(&self) -> bool {
1414 self.iter()
1415 .next()
1416 .is_some_and(|part| part.flags.prefix().is_unicode())
1417 }
1418
1419 pub fn as_slice(&self) -> &[StringLiteral] {
1421 match &self.inner {
1422 StringLiteralValueInner::Single(value) => std::slice::from_ref(value),
1423 StringLiteralValueInner::Concatenated(value) => value.strings.as_slice(),
1424 }
1425 }
1426
1427 fn as_mut_slice(&mut self) -> &mut [StringLiteral] {
1429 match &mut self.inner {
1430 StringLiteralValueInner::Single(value) => std::slice::from_mut(value),
1431 StringLiteralValueInner::Concatenated(value) => value.strings.as_mut_slice(),
1432 }
1433 }
1434
1435 pub fn iter(&self) -> Iter<'_, StringLiteral> {
1437 self.as_slice().iter()
1438 }
1439
1440 pub fn iter_mut(&mut self) -> IterMut<'_, StringLiteral> {
1443 self.as_mut_slice().iter_mut()
1444 }
1445
1446 pub fn is_empty(&self) -> bool {
1452 self.len() == 0
1453 }
1454
1455 pub fn len(&self) -> usize {
1458 self.iter().fold(0, |acc, part| acc + part.value.len())
1459 }
1460
1461 pub fn chars(&self) -> impl Iterator<Item = char> + Clone + '_ {
1463 self.iter().flat_map(|part| part.value.chars())
1464 }
1465
1466 pub fn to_str(&self) -> &str {
1471 match &self.inner {
1472 StringLiteralValueInner::Single(value) => value.as_str(),
1473 StringLiteralValueInner::Concatenated(value) => value.to_str(),
1474 }
1475 }
1476}
1477
1478impl<'a> IntoIterator for &'a StringLiteralValue {
1479 type Item = &'a StringLiteral;
1480 type IntoIter = Iter<'a, StringLiteral>;
1481
1482 fn into_iter(self) -> Self::IntoIter {
1483 self.iter()
1484 }
1485}
1486
1487impl<'a> IntoIterator for &'a mut StringLiteralValue {
1488 type Item = &'a mut StringLiteral;
1489 type IntoIter = IterMut<'a, StringLiteral>;
1490 fn into_iter(self) -> Self::IntoIter {
1491 self.iter_mut()
1492 }
1493}
1494
1495impl PartialEq<str> for StringLiteralValue {
1496 fn eq(&self, other: &str) -> bool {
1497 if self.len() != other.len() {
1498 return false;
1499 }
1500 self.chars().zip(other.chars()).all(|(c1, c2)| c1 == c2)
1502 }
1503}
1504
1505impl fmt::Display for StringLiteralValue {
1506 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1507 f.write_str(self.to_str())
1508 }
1509}
1510
1511#[derive(Clone, Debug, PartialEq)]
1513#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1514enum StringLiteralValueInner {
1515 Single(StringLiteral),
1517
1518 Concatenated(Box<ConcatenatedStringLiteral>),
1520}
1521
1522bitflags! {
1523 #[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
1524 struct StringLiteralFlagsInner: u8 {
1525 const DOUBLE = 1 << 0;
1528
1529 const TRIPLE_QUOTED = 1 << 1;
1532
1533 const U_PREFIX = 1 << 2;
1539
1540 const R_PREFIX_LOWER = 1 << 3;
1544
1545 const R_PREFIX_UPPER = 1 << 4;
1551
1552 const INVALID = 1 << 5;
1554
1555 const UNCLOSED = 1 << 6;
1557 }
1558}
1559
1560#[cfg(feature = "get-size")]
1561impl get_size2::GetSize for StringLiteralFlagsInner {}
1562
1563#[derive(Copy, Clone, Eq, PartialEq, Hash)]
1576#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1577pub struct StringLiteralFlags(StringLiteralFlagsInner);
1578
1579impl StringLiteralFlags {
1580 pub fn empty() -> Self {
1590 Self(StringLiteralFlagsInner::empty())
1591 }
1592
1593 #[must_use]
1594 pub fn with_quote_style(mut self, quote_style: Quote) -> Self {
1595 self.0
1596 .set(StringLiteralFlagsInner::DOUBLE, quote_style.is_double());
1597 self
1598 }
1599
1600 #[must_use]
1601 pub fn with_triple_quotes(mut self, triple_quotes: TripleQuotes) -> Self {
1602 self.0.set(
1603 StringLiteralFlagsInner::TRIPLE_QUOTED,
1604 triple_quotes.is_yes(),
1605 );
1606 self
1607 }
1608
1609 #[must_use]
1610 pub fn with_unclosed(mut self, unclosed: bool) -> Self {
1611 self.0.set(StringLiteralFlagsInner::UNCLOSED, unclosed);
1612 self
1613 }
1614
1615 #[must_use]
1616 pub fn with_prefix(self, prefix: StringLiteralPrefix) -> Self {
1617 let StringLiteralFlags(flags) = self;
1618 match prefix {
1619 StringLiteralPrefix::Empty => Self(
1620 flags
1621 - StringLiteralFlagsInner::R_PREFIX_LOWER
1622 - StringLiteralFlagsInner::R_PREFIX_UPPER
1623 - StringLiteralFlagsInner::U_PREFIX,
1624 ),
1625 StringLiteralPrefix::Raw { uppercase: false } => Self(
1626 (flags | StringLiteralFlagsInner::R_PREFIX_LOWER)
1627 - StringLiteralFlagsInner::R_PREFIX_UPPER
1628 - StringLiteralFlagsInner::U_PREFIX,
1629 ),
1630 StringLiteralPrefix::Raw { uppercase: true } => Self(
1631 (flags | StringLiteralFlagsInner::R_PREFIX_UPPER)
1632 - StringLiteralFlagsInner::R_PREFIX_LOWER
1633 - StringLiteralFlagsInner::U_PREFIX,
1634 ),
1635 StringLiteralPrefix::Unicode => Self(
1636 (flags | StringLiteralFlagsInner::U_PREFIX)
1637 - StringLiteralFlagsInner::R_PREFIX_LOWER
1638 - StringLiteralFlagsInner::R_PREFIX_UPPER,
1639 ),
1640 }
1641 }
1642
1643 #[must_use]
1644 pub fn with_invalid(mut self) -> Self {
1645 self.0 |= StringLiteralFlagsInner::INVALID;
1646 self
1647 }
1648
1649 pub const fn is_invalid(self) -> bool {
1651 self.0.contains(StringLiteralFlagsInner::INVALID)
1652 }
1653
1654 pub const fn prefix(self) -> StringLiteralPrefix {
1655 if self.0.contains(StringLiteralFlagsInner::U_PREFIX) {
1656 debug_assert!(
1657 !self.0.intersects(
1658 StringLiteralFlagsInner::R_PREFIX_LOWER
1659 .union(StringLiteralFlagsInner::R_PREFIX_UPPER)
1660 )
1661 );
1662 StringLiteralPrefix::Unicode
1663 } else if self.0.contains(StringLiteralFlagsInner::R_PREFIX_LOWER) {
1664 debug_assert!(!self.0.contains(StringLiteralFlagsInner::R_PREFIX_UPPER));
1665 StringLiteralPrefix::Raw { uppercase: false }
1666 } else if self.0.contains(StringLiteralFlagsInner::R_PREFIX_UPPER) {
1667 StringLiteralPrefix::Raw { uppercase: true }
1668 } else {
1669 StringLiteralPrefix::Empty
1670 }
1671 }
1672}
1673
1674impl StringFlags for StringLiteralFlags {
1675 fn quote_style(self) -> Quote {
1680 if self.0.contains(StringLiteralFlagsInner::DOUBLE) {
1681 Quote::Double
1682 } else {
1683 Quote::Single
1684 }
1685 }
1686
1687 fn triple_quotes(self) -> TripleQuotes {
1691 if self.0.contains(StringLiteralFlagsInner::TRIPLE_QUOTED) {
1692 TripleQuotes::Yes
1693 } else {
1694 TripleQuotes::No
1695 }
1696 }
1697
1698 fn prefix(self) -> AnyStringPrefix {
1699 AnyStringPrefix::Regular(self.prefix())
1700 }
1701
1702 fn is_unclosed(self) -> bool {
1703 self.0.intersects(StringLiteralFlagsInner::UNCLOSED)
1704 }
1705}
1706
1707impl fmt::Debug for StringLiteralFlags {
1708 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1709 f.debug_struct("StringLiteralFlags")
1710 .field("quote_style", &self.quote_style())
1711 .field("prefix", &self.prefix())
1712 .field("triple_quoted", &self.is_triple_quoted())
1713 .field("unclosed", &self.is_unclosed())
1714 .finish()
1715 }
1716}
1717
1718#[derive(Clone, Debug, PartialEq)]
1721#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1722pub struct StringLiteral {
1723 pub range: TextRange,
1724 pub node_index: AtomicNodeIndex,
1725 pub value: Box<str>,
1726 pub flags: StringLiteralFlags,
1727}
1728
1729impl Deref for StringLiteral {
1730 type Target = str;
1731
1732 fn deref(&self) -> &Self::Target {
1733 &self.value
1734 }
1735}
1736
1737impl StringLiteral {
1738 pub fn as_str(&self) -> &str {
1740 self
1741 }
1742
1743 pub fn invalid(range: TextRange) -> Self {
1745 Self {
1746 range,
1747 value: "".into(),
1748 node_index: AtomicNodeIndex::NONE,
1749 flags: StringLiteralFlags::empty().with_invalid(),
1750 }
1751 }
1752
1753 pub fn content_range(&self) -> TextRange {
1757 TextRange::new(
1758 self.start() + self.flags.opener_len(),
1759 self.end() - self.flags.closer_len(),
1760 )
1761 }
1762}
1763
1764impl From<StringLiteral> for Expr {
1765 fn from(payload: StringLiteral) -> Self {
1766 ExprStringLiteral {
1767 range: payload.range,
1768 node_index: AtomicNodeIndex::NONE,
1769 value: StringLiteralValue::single(payload),
1770 }
1771 .into()
1772 }
1773}
1774
1775#[derive(Clone)]
1778#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1779struct ConcatenatedStringLiteral {
1780 strings: Vec<StringLiteral>,
1782 value: OnceLock<Box<str>>,
1784}
1785
1786impl ConcatenatedStringLiteral {
1787 fn to_str(&self) -> &str {
1789 self.value.get_or_init(|| {
1790 let concatenated: String = self.strings.iter().map(StringLiteral::as_str).collect();
1791 concatenated.into_boxed_str()
1792 })
1793 }
1794}
1795
1796impl PartialEq for ConcatenatedStringLiteral {
1797 fn eq(&self, other: &Self) -> bool {
1798 if self.strings.len() != other.strings.len() {
1799 return false;
1800 }
1801 self.strings
1803 .iter()
1804 .zip(&other.strings)
1805 .all(|(s1, s2)| s1 == s2)
1806 }
1807}
1808
1809impl Debug for ConcatenatedStringLiteral {
1810 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1811 f.debug_struct("ConcatenatedStringLiteral")
1812 .field("strings", &self.strings)
1813 .field("value", &self.to_str())
1814 .finish()
1815 }
1816}
1817
1818impl ExprBytesLiteral {
1819 pub const fn as_single_part_bytestring(&self) -> Option<&BytesLiteral> {
1822 match &self.value.inner {
1823 BytesLiteralValueInner::Single(value) => Some(value),
1824 BytesLiteralValueInner::Concatenated(_) => None,
1825 }
1826 }
1827}
1828
1829#[derive(Clone, Debug, PartialEq)]
1831#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1832pub struct BytesLiteralValue {
1833 inner: BytesLiteralValueInner,
1834}
1835
1836impl BytesLiteralValue {
1837 pub fn single(value: BytesLiteral) -> Self {
1839 Self {
1840 inner: BytesLiteralValueInner::Single(value),
1841 }
1842 }
1843
1844 pub fn concatenated(values: Vec<BytesLiteral>) -> Self {
1852 assert!(
1853 values.len() > 1,
1854 "Use `BytesLiteralValue::single` to create single-part bytestrings"
1855 );
1856 Self {
1857 inner: BytesLiteralValueInner::Concatenated(values),
1858 }
1859 }
1860
1861 pub const fn is_implicit_concatenated(&self) -> bool {
1863 matches!(self.inner, BytesLiteralValueInner::Concatenated(_))
1864 }
1865
1866 pub fn as_slice(&self) -> &[BytesLiteral] {
1868 match &self.inner {
1869 BytesLiteralValueInner::Single(value) => std::slice::from_ref(value),
1870 BytesLiteralValueInner::Concatenated(value) => value.as_slice(),
1871 }
1872 }
1873
1874 fn as_mut_slice(&mut self) -> &mut [BytesLiteral] {
1876 match &mut self.inner {
1877 BytesLiteralValueInner::Single(value) => std::slice::from_mut(value),
1878 BytesLiteralValueInner::Concatenated(value) => value.as_mut_slice(),
1879 }
1880 }
1881
1882 pub fn iter(&self) -> Iter<'_, BytesLiteral> {
1884 self.as_slice().iter()
1885 }
1886
1887 pub fn iter_mut(&mut self) -> IterMut<'_, BytesLiteral> {
1890 self.as_mut_slice().iter_mut()
1891 }
1892
1893 pub fn is_empty(&self) -> bool {
1899 self.iter().all(|part| part.is_empty())
1900 }
1901
1902 pub fn len(&self) -> usize {
1904 self.iter().map(|part| part.len()).sum()
1905 }
1906
1907 pub fn bytes(&self) -> impl Iterator<Item = u8> + '_ {
1909 self.iter().flat_map(|part| part.as_slice().iter().copied())
1910 }
1911}
1912
1913impl<'a> IntoIterator for &'a BytesLiteralValue {
1914 type Item = &'a BytesLiteral;
1915 type IntoIter = Iter<'a, BytesLiteral>;
1916
1917 fn into_iter(self) -> Self::IntoIter {
1918 self.iter()
1919 }
1920}
1921
1922impl<'a> IntoIterator for &'a mut BytesLiteralValue {
1923 type Item = &'a mut BytesLiteral;
1924 type IntoIter = IterMut<'a, BytesLiteral>;
1925 fn into_iter(self) -> Self::IntoIter {
1926 self.iter_mut()
1927 }
1928}
1929
1930impl PartialEq<[u8]> for BytesLiteralValue {
1931 fn eq(&self, other: &[u8]) -> bool {
1932 if self.len() != other.len() {
1933 return false;
1934 }
1935 self.bytes()
1937 .zip(other.iter().copied())
1938 .all(|(b1, b2)| b1 == b2)
1939 }
1940}
1941
1942impl<'a> From<&'a BytesLiteralValue> for Cow<'a, [u8]> {
1943 fn from(value: &'a BytesLiteralValue) -> Self {
1944 match &value.inner {
1945 BytesLiteralValueInner::Single(BytesLiteral {
1946 value: bytes_value, ..
1947 }) => Cow::from(bytes_value.as_ref()),
1948 BytesLiteralValueInner::Concatenated(bytes_literal_vec) => Cow::Owned(
1949 bytes_literal_vec
1950 .iter()
1951 .flat_map(|bytes_literal| bytes_literal.value.to_vec())
1952 .collect::<Vec<u8>>(),
1953 ),
1954 }
1955 }
1956}
1957
1958#[derive(Clone, Debug, PartialEq)]
1960#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1961enum BytesLiteralValueInner {
1962 Single(BytesLiteral),
1964
1965 Concatenated(Vec<BytesLiteral>),
1967}
1968
1969bitflags! {
1970 #[derive(Default, Copy, Clone, PartialEq, Eq, Hash)]
1971 struct BytesLiteralFlagsInner: u8 {
1972 const DOUBLE = 1 << 0;
1975
1976 const TRIPLE_QUOTED = 1 << 1;
1979
1980 const R_PREFIX_LOWER = 1 << 2;
1983
1984 const R_PREFIX_UPPER = 1 << 3;
1989
1990 const INVALID = 1 << 4;
1992
1993 const UNCLOSED = 1 << 5;
1995 }
1996}
1997
1998#[cfg(feature = "get-size")]
1999impl get_size2::GetSize for BytesLiteralFlagsInner {}
2000
2001#[derive(Copy, Clone, Eq, PartialEq, Hash)]
2013#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2014pub struct BytesLiteralFlags(BytesLiteralFlagsInner);
2015
2016impl BytesLiteralFlags {
2017 pub fn empty() -> Self {
2027 Self(BytesLiteralFlagsInner::empty())
2028 }
2029
2030 #[must_use]
2031 pub fn with_quote_style(mut self, quote_style: Quote) -> Self {
2032 self.0
2033 .set(BytesLiteralFlagsInner::DOUBLE, quote_style.is_double());
2034 self
2035 }
2036
2037 #[must_use]
2038 pub fn with_triple_quotes(mut self, triple_quotes: TripleQuotes) -> Self {
2039 self.0.set(
2040 BytesLiteralFlagsInner::TRIPLE_QUOTED,
2041 triple_quotes.is_yes(),
2042 );
2043 self
2044 }
2045
2046 #[must_use]
2047 pub fn with_unclosed(mut self, unclosed: bool) -> Self {
2048 self.0.set(BytesLiteralFlagsInner::UNCLOSED, unclosed);
2049 self
2050 }
2051
2052 #[must_use]
2053 pub fn with_prefix(mut self, prefix: ByteStringPrefix) -> Self {
2054 match prefix {
2055 ByteStringPrefix::Regular => {
2056 self.0 -= BytesLiteralFlagsInner::R_PREFIX_LOWER;
2057 self.0 -= BytesLiteralFlagsInner::R_PREFIX_UPPER;
2058 }
2059 ByteStringPrefix::Raw { uppercase_r } => {
2060 self.0
2061 .set(BytesLiteralFlagsInner::R_PREFIX_UPPER, uppercase_r);
2062 self.0
2063 .set(BytesLiteralFlagsInner::R_PREFIX_LOWER, !uppercase_r);
2064 }
2065 }
2066 self
2067 }
2068
2069 #[must_use]
2070 pub fn with_invalid(mut self) -> Self {
2071 self.0 |= BytesLiteralFlagsInner::INVALID;
2072 self
2073 }
2074
2075 pub const fn is_invalid(self) -> bool {
2077 self.0.contains(BytesLiteralFlagsInner::INVALID)
2078 }
2079
2080 pub const fn prefix(self) -> ByteStringPrefix {
2081 if self.0.contains(BytesLiteralFlagsInner::R_PREFIX_LOWER) {
2082 debug_assert!(!self.0.contains(BytesLiteralFlagsInner::R_PREFIX_UPPER));
2083 ByteStringPrefix::Raw { uppercase_r: false }
2084 } else if self.0.contains(BytesLiteralFlagsInner::R_PREFIX_UPPER) {
2085 ByteStringPrefix::Raw { uppercase_r: true }
2086 } else {
2087 ByteStringPrefix::Regular
2088 }
2089 }
2090}
2091
2092impl StringFlags for BytesLiteralFlags {
2093 fn triple_quotes(self) -> TripleQuotes {
2097 if self.0.contains(BytesLiteralFlagsInner::TRIPLE_QUOTED) {
2098 TripleQuotes::Yes
2099 } else {
2100 TripleQuotes::No
2101 }
2102 }
2103
2104 fn quote_style(self) -> Quote {
2109 if self.0.contains(BytesLiteralFlagsInner::DOUBLE) {
2110 Quote::Double
2111 } else {
2112 Quote::Single
2113 }
2114 }
2115
2116 fn prefix(self) -> AnyStringPrefix {
2117 AnyStringPrefix::Bytes(self.prefix())
2118 }
2119
2120 fn is_unclosed(self) -> bool {
2121 self.0.intersects(BytesLiteralFlagsInner::UNCLOSED)
2122 }
2123}
2124
2125impl fmt::Debug for BytesLiteralFlags {
2126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2127 f.debug_struct("BytesLiteralFlags")
2128 .field("quote_style", &self.quote_style())
2129 .field("prefix", &self.prefix())
2130 .field("triple_quoted", &self.is_triple_quoted())
2131 .field("unclosed", &self.is_unclosed())
2132 .finish()
2133 }
2134}
2135
2136#[derive(Clone, Debug, PartialEq)]
2139#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2140pub struct BytesLiteral {
2141 pub range: TextRange,
2142 pub node_index: AtomicNodeIndex,
2143 pub value: Box<[u8]>,
2144 pub flags: BytesLiteralFlags,
2145}
2146
2147impl Deref for BytesLiteral {
2148 type Target = [u8];
2149
2150 fn deref(&self) -> &Self::Target {
2151 &self.value
2152 }
2153}
2154
2155impl BytesLiteral {
2156 pub fn as_slice(&self) -> &[u8] {
2158 self
2159 }
2160
2161 pub fn invalid(range: TextRange) -> Self {
2163 Self {
2164 range,
2165 value: Box::new([]),
2166 node_index: AtomicNodeIndex::NONE,
2167 flags: BytesLiteralFlags::empty().with_invalid(),
2168 }
2169 }
2170
2171 pub fn content_range(&self) -> TextRange {
2175 TextRange::new(
2176 self.start() + self.flags.opener_len(),
2177 self.end() - self.flags.closer_len(),
2178 )
2179 }
2180}
2181
2182impl From<BytesLiteral> for Expr {
2183 fn from(payload: BytesLiteral) -> Self {
2184 ExprBytesLiteral {
2185 range: payload.range,
2186 node_index: AtomicNodeIndex::NONE,
2187 value: BytesLiteralValue::single(payload),
2188 }
2189 .into()
2190 }
2191}
2192
2193bitflags! {
2194 #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
2203 struct AnyStringFlagsInner: u16 {
2204 const DOUBLE = 1 << 0;
2207
2208 const TRIPLE_QUOTED = 1 << 1;
2211
2212 const U_PREFIX = 1 << 2;
2216
2217 const B_PREFIX = 1 << 3;
2223
2224 const F_PREFIX = 1 << 4;
2228
2229 const T_PREFIX = 1 << 5;
2233
2234 const R_PREFIX_LOWER = 1 << 6;
2239
2240 const R_PREFIX_UPPER = 1 << 7;
2246
2247 const UNCLOSED = 1 << 8;
2249 }
2250}
2251
2252#[derive(Clone, Copy, PartialEq, Eq, Hash)]
2253pub struct AnyStringFlags(AnyStringFlagsInner);
2254
2255impl AnyStringFlags {
2256 #[must_use]
2257 pub fn with_prefix(mut self, prefix: AnyStringPrefix) -> Self {
2258 self.0 |= match prefix {
2259 AnyStringPrefix::Regular(StringLiteralPrefix::Empty) => AnyStringFlagsInner::empty(),
2261 AnyStringPrefix::Regular(StringLiteralPrefix::Unicode) => AnyStringFlagsInner::U_PREFIX,
2262 AnyStringPrefix::Regular(StringLiteralPrefix::Raw { uppercase: false }) => {
2263 AnyStringFlagsInner::R_PREFIX_LOWER
2264 }
2265 AnyStringPrefix::Regular(StringLiteralPrefix::Raw { uppercase: true }) => {
2266 AnyStringFlagsInner::R_PREFIX_UPPER
2267 }
2268
2269 AnyStringPrefix::Bytes(ByteStringPrefix::Regular) => AnyStringFlagsInner::B_PREFIX,
2271 AnyStringPrefix::Bytes(ByteStringPrefix::Raw { uppercase_r: false }) => {
2272 AnyStringFlagsInner::B_PREFIX.union(AnyStringFlagsInner::R_PREFIX_LOWER)
2273 }
2274 AnyStringPrefix::Bytes(ByteStringPrefix::Raw { uppercase_r: true }) => {
2275 AnyStringFlagsInner::B_PREFIX.union(AnyStringFlagsInner::R_PREFIX_UPPER)
2276 }
2277
2278 AnyStringPrefix::Format(FStringPrefix::Regular) => AnyStringFlagsInner::F_PREFIX,
2280 AnyStringPrefix::Format(FStringPrefix::Raw { uppercase_r: false }) => {
2281 AnyStringFlagsInner::F_PREFIX.union(AnyStringFlagsInner::R_PREFIX_LOWER)
2282 }
2283 AnyStringPrefix::Format(FStringPrefix::Raw { uppercase_r: true }) => {
2284 AnyStringFlagsInner::F_PREFIX.union(AnyStringFlagsInner::R_PREFIX_UPPER)
2285 }
2286
2287 AnyStringPrefix::Template(TStringPrefix::Regular) => AnyStringFlagsInner::T_PREFIX,
2289 AnyStringPrefix::Template(TStringPrefix::Raw { uppercase_r: false }) => {
2290 AnyStringFlagsInner::T_PREFIX.union(AnyStringFlagsInner::R_PREFIX_LOWER)
2291 }
2292 AnyStringPrefix::Template(TStringPrefix::Raw { uppercase_r: true }) => {
2293 AnyStringFlagsInner::T_PREFIX.union(AnyStringFlagsInner::R_PREFIX_UPPER)
2294 }
2295 };
2296 self
2297 }
2298
2299 pub fn new(prefix: AnyStringPrefix, quotes: Quote, triple_quotes: TripleQuotes) -> Self {
2300 Self(AnyStringFlagsInner::empty())
2301 .with_prefix(prefix)
2302 .with_quote_style(quotes)
2303 .with_triple_quotes(triple_quotes)
2304 }
2305
2306 pub const fn is_u_string(self) -> bool {
2308 self.0.contains(AnyStringFlagsInner::U_PREFIX)
2309 }
2310
2311 pub const fn is_raw_string(self) -> bool {
2313 self.0.intersects(
2314 AnyStringFlagsInner::R_PREFIX_LOWER.union(AnyStringFlagsInner::R_PREFIX_UPPER),
2315 )
2316 }
2317
2318 pub const fn is_interpolated_string(self) -> bool {
2320 self.0
2321 .intersects(AnyStringFlagsInner::F_PREFIX.union(AnyStringFlagsInner::T_PREFIX))
2322 }
2323
2324 pub const fn is_byte_string(self) -> bool {
2326 self.0.contains(AnyStringFlagsInner::B_PREFIX)
2327 }
2328
2329 #[must_use]
2330 pub fn with_quote_style(mut self, quotes: Quote) -> Self {
2331 match quotes {
2332 Quote::Double => self.0 |= AnyStringFlagsInner::DOUBLE,
2333 Quote::Single => self.0 -= AnyStringFlagsInner::DOUBLE,
2334 }
2335 self
2336 }
2337
2338 #[must_use]
2339 pub fn with_triple_quotes(mut self, triple_quotes: TripleQuotes) -> Self {
2340 self.0
2341 .set(AnyStringFlagsInner::TRIPLE_QUOTED, triple_quotes.is_yes());
2342 self
2343 }
2344
2345 #[must_use]
2346 pub fn with_unclosed(mut self, unclosed: bool) -> Self {
2347 self.0.set(AnyStringFlagsInner::UNCLOSED, unclosed);
2348 self
2349 }
2350}
2351
2352impl StringFlags for AnyStringFlags {
2353 fn quote_style(self) -> Quote {
2355 if self.0.contains(AnyStringFlagsInner::DOUBLE) {
2356 Quote::Double
2357 } else {
2358 Quote::Single
2359 }
2360 }
2361
2362 fn triple_quotes(self) -> TripleQuotes {
2363 if self.0.contains(AnyStringFlagsInner::TRIPLE_QUOTED) {
2364 TripleQuotes::Yes
2365 } else {
2366 TripleQuotes::No
2367 }
2368 }
2369
2370 fn prefix(self) -> AnyStringPrefix {
2371 let AnyStringFlags(flags) = self;
2372
2373 if flags.contains(AnyStringFlagsInner::F_PREFIX) {
2375 if flags.contains(AnyStringFlagsInner::R_PREFIX_LOWER) {
2376 return AnyStringPrefix::Format(FStringPrefix::Raw { uppercase_r: false });
2377 }
2378 if flags.contains(AnyStringFlagsInner::R_PREFIX_UPPER) {
2379 return AnyStringPrefix::Format(FStringPrefix::Raw { uppercase_r: true });
2380 }
2381 return AnyStringPrefix::Format(FStringPrefix::Regular);
2382 }
2383
2384 if flags.contains(AnyStringFlagsInner::T_PREFIX) {
2386 if flags.contains(AnyStringFlagsInner::R_PREFIX_LOWER) {
2387 return AnyStringPrefix::Template(TStringPrefix::Raw { uppercase_r: false });
2388 }
2389 if flags.contains(AnyStringFlagsInner::R_PREFIX_UPPER) {
2390 return AnyStringPrefix::Template(TStringPrefix::Raw { uppercase_r: true });
2391 }
2392 return AnyStringPrefix::Template(TStringPrefix::Regular);
2393 }
2394
2395 if flags.contains(AnyStringFlagsInner::B_PREFIX) {
2397 if flags.contains(AnyStringFlagsInner::R_PREFIX_LOWER) {
2398 return AnyStringPrefix::Bytes(ByteStringPrefix::Raw { uppercase_r: false });
2399 }
2400 if flags.contains(AnyStringFlagsInner::R_PREFIX_UPPER) {
2401 return AnyStringPrefix::Bytes(ByteStringPrefix::Raw { uppercase_r: true });
2402 }
2403 return AnyStringPrefix::Bytes(ByteStringPrefix::Regular);
2404 }
2405
2406 if flags.contains(AnyStringFlagsInner::R_PREFIX_LOWER) {
2408 return AnyStringPrefix::Regular(StringLiteralPrefix::Raw { uppercase: false });
2409 }
2410 if flags.contains(AnyStringFlagsInner::R_PREFIX_UPPER) {
2411 return AnyStringPrefix::Regular(StringLiteralPrefix::Raw { uppercase: true });
2412 }
2413 if flags.contains(AnyStringFlagsInner::U_PREFIX) {
2414 return AnyStringPrefix::Regular(StringLiteralPrefix::Unicode);
2415 }
2416 AnyStringPrefix::Regular(StringLiteralPrefix::Empty)
2417 }
2418
2419 fn is_unclosed(self) -> bool {
2420 self.0.intersects(AnyStringFlagsInner::UNCLOSED)
2421 }
2422}
2423
2424impl fmt::Debug for AnyStringFlags {
2425 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2426 f.debug_struct("AnyStringFlags")
2427 .field("prefix", &self.prefix())
2428 .field("triple_quoted", &self.is_triple_quoted())
2429 .field("quote_style", &self.quote_style())
2430 .field("unclosed", &self.is_unclosed())
2431 .finish()
2432 }
2433}
2434
2435impl From<AnyStringFlags> for StringLiteralFlags {
2436 fn from(value: AnyStringFlags) -> StringLiteralFlags {
2437 let AnyStringPrefix::Regular(prefix) = value.prefix() else {
2438 unreachable!(
2439 "Should never attempt to convert {} into a regular string",
2440 value.prefix()
2441 )
2442 };
2443 StringLiteralFlags::empty()
2444 .with_quote_style(value.quote_style())
2445 .with_prefix(prefix)
2446 .with_triple_quotes(value.triple_quotes())
2447 .with_unclosed(value.is_unclosed())
2448 }
2449}
2450
2451impl From<StringLiteralFlags> for AnyStringFlags {
2452 fn from(value: StringLiteralFlags) -> Self {
2453 value.as_any_string_flags()
2454 }
2455}
2456
2457impl From<AnyStringFlags> for BytesLiteralFlags {
2458 fn from(value: AnyStringFlags) -> BytesLiteralFlags {
2459 let AnyStringPrefix::Bytes(bytestring_prefix) = value.prefix() else {
2460 unreachable!(
2461 "Should never attempt to convert {} into a bytestring",
2462 value.prefix()
2463 )
2464 };
2465 BytesLiteralFlags::empty()
2466 .with_quote_style(value.quote_style())
2467 .with_prefix(bytestring_prefix)
2468 .with_triple_quotes(value.triple_quotes())
2469 .with_unclosed(value.is_unclosed())
2470 }
2471}
2472
2473impl From<BytesLiteralFlags> for AnyStringFlags {
2474 fn from(value: BytesLiteralFlags) -> Self {
2475 value.as_any_string_flags()
2476 }
2477}
2478
2479impl From<AnyStringFlags> for FStringFlags {
2480 fn from(value: AnyStringFlags) -> FStringFlags {
2481 let AnyStringPrefix::Format(prefix) = value.prefix() else {
2482 unreachable!(
2483 "Should never attempt to convert {} into an f-string",
2484 value.prefix()
2485 )
2486 };
2487 FStringFlags::empty()
2488 .with_quote_style(value.quote_style())
2489 .with_prefix(prefix)
2490 .with_triple_quotes(value.triple_quotes())
2491 .with_unclosed(value.is_unclosed())
2492 }
2493}
2494
2495impl From<FStringFlags> for AnyStringFlags {
2496 fn from(value: FStringFlags) -> Self {
2497 value.as_any_string_flags()
2498 }
2499}
2500
2501impl From<AnyStringFlags> for TStringFlags {
2502 fn from(value: AnyStringFlags) -> TStringFlags {
2503 let AnyStringPrefix::Template(prefix) = value.prefix() else {
2504 unreachable!(
2505 "Should never attempt to convert {} into a t-string",
2506 value.prefix()
2507 )
2508 };
2509 TStringFlags::empty()
2510 .with_quote_style(value.quote_style())
2511 .with_prefix(prefix)
2512 .with_triple_quotes(value.triple_quotes())
2513 .with_unclosed(value.is_unclosed())
2514 }
2515}
2516
2517impl From<TStringFlags> for AnyStringFlags {
2518 fn from(value: TStringFlags) -> Self {
2519 value.as_any_string_flags()
2520 }
2521}
2522
2523#[derive(Clone, Debug, PartialEq, is_macro::Is)]
2524#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2525pub enum Number {
2526 Int(int::Int),
2527 Float(f64),
2528 Complex { real: f64, imag: f64 },
2529}
2530
2531impl ExprName {
2532 pub fn id(&self) -> &Name {
2533 &self.id
2534 }
2535
2536 pub const fn is_invalid(&self) -> bool {
2540 matches!(self.ctx, ExprContext::Invalid)
2541 }
2542}
2543
2544impl ExprList {
2545 pub fn iter(&self) -> std::slice::Iter<'_, Expr> {
2546 self.elts.iter()
2547 }
2548
2549 pub fn len(&self) -> usize {
2550 self.elts.len()
2551 }
2552
2553 pub fn is_empty(&self) -> bool {
2554 self.elts.is_empty()
2555 }
2556}
2557
2558impl<'a> IntoIterator for &'a ExprList {
2559 type IntoIter = std::slice::Iter<'a, Expr>;
2560 type Item = &'a Expr;
2561
2562 fn into_iter(self) -> Self::IntoIter {
2563 self.iter()
2564 }
2565}
2566
2567impl ExprTuple {
2568 pub fn iter(&self) -> std::slice::Iter<'_, Expr> {
2569 self.elts.iter()
2570 }
2571
2572 pub fn len(&self) -> usize {
2573 self.elts.len()
2574 }
2575
2576 pub fn is_empty(&self) -> bool {
2577 self.elts.is_empty()
2578 }
2579}
2580
2581impl<'a> IntoIterator for &'a ExprTuple {
2582 type IntoIter = std::slice::Iter<'a, Expr>;
2583 type Item = &'a Expr;
2584
2585 fn into_iter(self) -> Self::IntoIter {
2586 self.iter()
2587 }
2588}
2589
2590#[derive(Clone, Debug, PartialEq, is_macro::Is, Copy, Hash, Eq)]
2592#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2593pub enum ExprContext {
2594 Load,
2595 Store,
2596 Del,
2597 Invalid,
2598}
2599
2600#[derive(Clone, Debug, PartialEq, is_macro::Is, Copy, Hash, Eq)]
2602#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2603pub enum BoolOp {
2604 And,
2605 Or,
2606}
2607
2608impl BoolOp {
2609 pub const fn as_str(&self) -> &'static str {
2610 match self {
2611 BoolOp::And => "and",
2612 BoolOp::Or => "or",
2613 }
2614 }
2615}
2616
2617impl fmt::Display for BoolOp {
2618 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2619 f.write_str(self.as_str())
2620 }
2621}
2622
2623#[derive(Clone, Debug, PartialEq, is_macro::Is, Copy, Hash, Eq)]
2625#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2626pub enum Operator {
2627 Add,
2628 Sub,
2629 Mult,
2630 MatMult,
2631 Div,
2632 Mod,
2633 Pow,
2634 LShift,
2635 RShift,
2636 BitOr,
2637 BitXor,
2638 BitAnd,
2639 FloorDiv,
2640}
2641
2642impl Operator {
2643 pub const fn as_str(&self) -> &'static str {
2644 match self {
2645 Operator::Add => "+",
2646 Operator::Sub => "-",
2647 Operator::Mult => "*",
2648 Operator::MatMult => "@",
2649 Operator::Div => "/",
2650 Operator::Mod => "%",
2651 Operator::Pow => "**",
2652 Operator::LShift => "<<",
2653 Operator::RShift => ">>",
2654 Operator::BitOr => "|",
2655 Operator::BitXor => "^",
2656 Operator::BitAnd => "&",
2657 Operator::FloorDiv => "//",
2658 }
2659 }
2660
2661 pub const fn dunder(self) -> &'static str {
2663 match self {
2664 Operator::Add => "__add__",
2665 Operator::Sub => "__sub__",
2666 Operator::Mult => "__mul__",
2667 Operator::MatMult => "__matmul__",
2668 Operator::Div => "__truediv__",
2669 Operator::Mod => "__mod__",
2670 Operator::Pow => "__pow__",
2671 Operator::LShift => "__lshift__",
2672 Operator::RShift => "__rshift__",
2673 Operator::BitOr => "__or__",
2674 Operator::BitXor => "__xor__",
2675 Operator::BitAnd => "__and__",
2676 Operator::FloorDiv => "__floordiv__",
2677 }
2678 }
2679
2680 pub const fn in_place_dunder(self) -> &'static str {
2682 match self {
2683 Operator::Add => "__iadd__",
2684 Operator::Sub => "__isub__",
2685 Operator::Mult => "__imul__",
2686 Operator::MatMult => "__imatmul__",
2687 Operator::Div => "__itruediv__",
2688 Operator::Mod => "__imod__",
2689 Operator::Pow => "__ipow__",
2690 Operator::LShift => "__ilshift__",
2691 Operator::RShift => "__irshift__",
2692 Operator::BitOr => "__ior__",
2693 Operator::BitXor => "__ixor__",
2694 Operator::BitAnd => "__iand__",
2695 Operator::FloorDiv => "__ifloordiv__",
2696 }
2697 }
2698
2699 pub const fn reflected_dunder(self) -> &'static str {
2701 match self {
2702 Operator::Add => "__radd__",
2703 Operator::Sub => "__rsub__",
2704 Operator::Mult => "__rmul__",
2705 Operator::MatMult => "__rmatmul__",
2706 Operator::Div => "__rtruediv__",
2707 Operator::Mod => "__rmod__",
2708 Operator::Pow => "__rpow__",
2709 Operator::LShift => "__rlshift__",
2710 Operator::RShift => "__rrshift__",
2711 Operator::BitOr => "__ror__",
2712 Operator::BitXor => "__rxor__",
2713 Operator::BitAnd => "__rand__",
2714 Operator::FloorDiv => "__rfloordiv__",
2715 }
2716 }
2717}
2718
2719impl fmt::Display for Operator {
2720 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2721 f.write_str(self.as_str())
2722 }
2723}
2724
2725#[derive(Clone, Debug, PartialEq, is_macro::Is, Copy, Hash, Eq)]
2727#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2728pub enum UnaryOp {
2729 Invert,
2730 Not,
2731 UAdd,
2732 USub,
2733}
2734
2735impl UnaryOp {
2736 pub const fn as_str(&self) -> &'static str {
2737 match self {
2738 UnaryOp::Invert => "~",
2739 UnaryOp::Not => "not",
2740 UnaryOp::UAdd => "+",
2741 UnaryOp::USub => "-",
2742 }
2743 }
2744}
2745
2746impl fmt::Display for UnaryOp {
2747 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2748 f.write_str(self.as_str())
2749 }
2750}
2751
2752#[derive(Clone, Debug, PartialEq, is_macro::Is, Copy, Hash, Eq)]
2754#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2755pub enum CmpOp {
2756 Eq,
2757 NotEq,
2758 Lt,
2759 LtE,
2760 Gt,
2761 GtE,
2762 Is,
2763 IsNot,
2764 In,
2765 NotIn,
2766}
2767
2768impl CmpOp {
2769 pub const fn as_str(&self) -> &'static str {
2770 match self {
2771 CmpOp::Eq => "==",
2772 CmpOp::NotEq => "!=",
2773 CmpOp::Lt => "<",
2774 CmpOp::LtE => "<=",
2775 CmpOp::Gt => ">",
2776 CmpOp::GtE => ">=",
2777 CmpOp::Is => "is",
2778 CmpOp::IsNot => "is not",
2779 CmpOp::In => "in",
2780 CmpOp::NotIn => "not in",
2781 }
2782 }
2783
2784 #[must_use]
2785 pub const fn negate(&self) -> Self {
2786 match self {
2787 CmpOp::Eq => CmpOp::NotEq,
2788 CmpOp::NotEq => CmpOp::Eq,
2789 CmpOp::Lt => CmpOp::GtE,
2790 CmpOp::LtE => CmpOp::Gt,
2791 CmpOp::Gt => CmpOp::LtE,
2792 CmpOp::GtE => CmpOp::Lt,
2793 CmpOp::Is => CmpOp::IsNot,
2794 CmpOp::IsNot => CmpOp::Is,
2795 CmpOp::In => CmpOp::NotIn,
2796 CmpOp::NotIn => CmpOp::In,
2797 }
2798 }
2799}
2800
2801impl fmt::Display for CmpOp {
2802 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2803 f.write_str(self.as_str())
2804 }
2805}
2806
2807#[derive(Clone, Debug, PartialEq)]
2809#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2810pub struct Comprehension {
2811 pub range: TextRange,
2812 pub node_index: AtomicNodeIndex,
2813 pub target: Expr,
2814 pub iter: Expr,
2815 pub ifs: Vec<Expr>,
2816 pub is_async: bool,
2817}
2818
2819#[derive(Clone, Debug, PartialEq)]
2821#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2822pub struct ExceptHandlerExceptHandler {
2823 pub range: TextRange,
2824 pub node_index: AtomicNodeIndex,
2825 pub type_: Option<Box<Expr>>,
2826 pub name: Option<Identifier>,
2827 pub body: Suite,
2828}
2829
2830#[derive(Clone, Debug, PartialEq)]
2832#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2833pub struct Parameter {
2834 pub range: TextRange,
2835 pub node_index: AtomicNodeIndex,
2836 pub name: Identifier,
2837 pub annotation: Option<Box<Expr>>,
2838}
2839
2840impl Parameter {
2841 pub const fn name(&self) -> &Identifier {
2842 &self.name
2843 }
2844
2845 pub fn annotation(&self) -> Option<&Expr> {
2846 self.annotation.as_deref()
2847 }
2848}
2849
2850#[derive(Clone, Debug, PartialEq)]
2852#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2853pub struct Keyword {
2854 pub range: TextRange,
2855 pub node_index: AtomicNodeIndex,
2856 pub arg: Option<Identifier>,
2857 pub value: Expr,
2858}
2859
2860#[derive(Clone, Debug, PartialEq)]
2862#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2863pub struct Alias {
2864 pub range: TextRange,
2865 pub node_index: AtomicNodeIndex,
2866 pub name: Identifier,
2867 pub asname: Option<Identifier>,
2868}
2869
2870#[derive(Clone, Debug, PartialEq)]
2872#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2873pub struct WithItem {
2874 pub range: TextRange,
2875 pub node_index: AtomicNodeIndex,
2876 pub context_expr: Expr,
2877 pub optional_vars: Option<Box<Expr>>,
2878}
2879
2880#[derive(Clone, Debug, PartialEq)]
2882#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2883pub struct MatchCase {
2884 pub range: TextRange,
2885 pub node_index: AtomicNodeIndex,
2886 pub pattern: Pattern,
2887 pub guard: Option<Box<Expr>>,
2888 pub body: Suite,
2889}
2890
2891impl Pattern {
2892 pub fn is_irrefutable(&self) -> bool {
2896 self.irrefutable_pattern().is_some()
2897 }
2898
2899 pub fn irrefutable_pattern(&self) -> Option<IrrefutablePattern> {
2901 match self {
2902 Pattern::MatchAs(PatternMatchAs {
2903 pattern,
2904 name,
2905 range,
2906 node_index,
2907 }) => match pattern {
2908 Some(pattern) => pattern.irrefutable_pattern(),
2909 None => match name {
2910 Some(name) => Some(IrrefutablePattern {
2911 kind: IrrefutablePatternKind::Name(name.id.clone()),
2912 range: *range,
2913 node_index: node_index.clone(),
2914 }),
2915 None => Some(IrrefutablePattern {
2916 kind: IrrefutablePatternKind::Wildcard,
2917 range: *range,
2918 node_index: node_index.clone(),
2919 }),
2920 },
2921 },
2922 Pattern::MatchOr(PatternMatchOr { patterns, .. }) => {
2923 patterns.iter().find_map(Pattern::irrefutable_pattern)
2924 }
2925 _ => None,
2926 }
2927 }
2928
2929 pub fn is_wildcard(&self) -> bool {
2941 match self {
2942 Pattern::MatchAs(PatternMatchAs { pattern, .. }) => {
2943 pattern.as_deref().is_none_or(Pattern::is_wildcard)
2944 }
2945 Pattern::MatchOr(PatternMatchOr { patterns, .. }) => {
2946 patterns.iter().all(Pattern::is_wildcard)
2947 }
2948 _ => false,
2949 }
2950 }
2951}
2952
2953pub struct IrrefutablePattern {
2954 pub kind: IrrefutablePatternKind,
2955 pub range: TextRange,
2956 pub node_index: AtomicNodeIndex,
2957}
2958
2959#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2960#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2961pub enum IrrefutablePatternKind {
2962 Name(Name),
2963 Wildcard,
2964}
2965
2966#[derive(Clone, Debug, PartialEq)]
2971#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2972pub struct PatternArguments {
2973 pub range: TextRange,
2974 pub node_index: AtomicNodeIndex,
2975 pub patterns: ThinVec<Pattern>,
2976 pub keywords: Vec<PatternKeyword>,
2977}
2978
2979#[derive(Clone, Debug, PartialEq)]
2984#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
2985pub struct PatternKeyword {
2986 pub range: TextRange,
2987 pub node_index: AtomicNodeIndex,
2988 pub attr: Identifier,
2989 pub pattern: Pattern,
2990}
2991
2992impl PatternArguments {
2993 pub fn iter_source_order(&self) -> PatternArgumentsSourceOrder<'_> {
2995 PatternArgumentsSourceOrder {
2996 patterns: &self.patterns,
2997 keywords: &self.keywords,
2998 next_pattern: 0,
2999 next_keyword: 0,
3000 }
3001 }
3002}
3003
3004#[derive(Clone)]
3006pub struct PatternArgumentsSourceOrder<'a> {
3007 patterns: &'a [Pattern],
3008 keywords: &'a [PatternKeyword],
3009 next_pattern: usize,
3010 next_keyword: usize,
3011}
3012
3013#[derive(Copy, Clone, Debug, PartialEq)]
3015pub enum PatternOrKeyword<'a> {
3016 Pattern(&'a Pattern),
3017 Keyword(&'a PatternKeyword),
3018}
3019
3020impl<'a> Iterator for PatternArgumentsSourceOrder<'a> {
3021 type Item = PatternOrKeyword<'a>;
3022
3023 fn next(&mut self) -> Option<Self::Item> {
3024 let pattern = self.patterns.get(self.next_pattern);
3025 let keyword = self.keywords.get(self.next_keyword);
3026
3027 if let Some(pattern) = pattern
3028 && keyword.is_none_or(|keyword| pattern.start() <= keyword.start())
3029 {
3030 self.next_pattern += 1;
3031 Some(PatternOrKeyword::Pattern(pattern))
3032 } else if let Some(keyword) = keyword {
3033 self.next_keyword += 1;
3034 Some(PatternOrKeyword::Keyword(keyword))
3035 } else {
3036 None
3037 }
3038 }
3039}
3040
3041impl FusedIterator for PatternArgumentsSourceOrder<'_> {}
3042
3043impl TypeParam {
3044 pub const fn name(&self) -> &Identifier {
3045 match self {
3046 Self::TypeVar(x) => &x.name,
3047 Self::ParamSpec(x) => &x.name,
3048 Self::TypeVarTuple(x) => &x.name,
3049 }
3050 }
3051
3052 pub fn default(&self) -> Option<&Expr> {
3053 match self {
3054 Self::TypeVar(x) => x.default.as_deref(),
3055 Self::ParamSpec(x) => x.default.as_deref(),
3056 Self::TypeVarTuple(x) => x.default.as_deref(),
3057 }
3058 }
3059}
3060
3061#[derive(Clone, Debug, PartialEq)]
3063#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
3064pub struct Decorator {
3065 pub range: TextRange,
3066 pub node_index: AtomicNodeIndex,
3067 pub expression: Expr,
3068}
3069
3070#[derive(Debug, PartialEq, Clone, Copy)]
3072pub enum AnyParameterRef<'a> {
3073 Variadic(&'a Parameter),
3080
3081 NonVariadic(&'a ParameterWithDefault),
3088}
3089
3090impl<'a> AnyParameterRef<'a> {
3091 pub const fn as_parameter(self) -> &'a Parameter {
3092 match self {
3093 Self::NonVariadic(param) => ¶m.parameter,
3094 Self::Variadic(param) => param,
3095 }
3096 }
3097
3098 pub const fn name(self) -> &'a Identifier {
3099 &self.as_parameter().name
3100 }
3101
3102 pub const fn is_variadic(self) -> bool {
3103 matches!(self, Self::Variadic(_))
3104 }
3105
3106 pub fn annotation(self) -> Option<&'a Expr> {
3107 self.as_parameter().annotation.as_deref()
3108 }
3109
3110 pub fn default(self) -> Option<&'a Expr> {
3111 match self {
3112 Self::NonVariadic(param) => param.default.as_deref(),
3113 Self::Variadic(_) => None,
3114 }
3115 }
3116}
3117
3118impl Ranged for AnyParameterRef<'_> {
3119 fn range(&self) -> TextRange {
3120 match self {
3121 Self::NonVariadic(param) => param.range,
3122 Self::Variadic(param) => param.range,
3123 }
3124 }
3125}
3126
3127#[derive(Clone, Debug, PartialEq, Default)]
3138#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
3139pub struct Parameters {
3140 pub range: TextRange,
3141 pub node_index: AtomicNodeIndex,
3142 pub posonlyargs: ThinVec<ParameterWithDefault>,
3143 pub args: ThinVec<ParameterWithDefault>,
3144 pub vararg: Option<Box<Parameter>>,
3145 pub kwonlyargs: ThinVec<ParameterWithDefault>,
3146 pub kwarg: Option<Box<Parameter>>,
3147}
3148
3149impl Parameters {
3150 pub fn iter_non_variadic_params(&self) -> impl Iterator<Item = &ParameterWithDefault> {
3155 self.posonlyargs
3156 .iter()
3157 .chain(&self.args)
3158 .chain(&self.kwonlyargs)
3159 }
3160
3161 pub fn find(&self, name: &str) -> Option<&ParameterWithDefault> {
3163 self.iter_non_variadic_params()
3164 .find(|arg| arg.parameter.name.as_str() == name)
3165 }
3166
3167 pub fn index(&self, name: &str) -> Option<usize> {
3169 self.iter_non_variadic_params()
3170 .position(|arg| arg.parameter.name.as_str() == name)
3171 }
3172
3173 pub fn iter(&self) -> ParametersIterator<'_> {
3175 ParametersIterator::new(self)
3176 }
3177
3178 pub fn len(&self) -> usize {
3180 let Parameters {
3181 range: _,
3182 node_index: _,
3183 posonlyargs,
3184 args,
3185 vararg,
3186 kwonlyargs,
3187 kwarg,
3188 } = self;
3189 posonlyargs
3196 .len()
3197 .checked_add(args.len())
3198 .and_then(|length| length.checked_add(usize::from(vararg.is_some())))
3199 .and_then(|length| length.checked_add(kwonlyargs.len()))
3200 .and_then(|length| length.checked_add(usize::from(kwarg.is_some())))
3201 .expect("Failed to fit the number of parameters into a usize")
3202 }
3203
3204 pub fn includes(&self, name: &str) -> bool {
3206 self.iter().any(|param| param.name() == name)
3207 }
3208
3209 pub fn is_empty(&self) -> bool {
3211 self.posonlyargs.is_empty()
3212 && self.args.is_empty()
3213 && self.kwonlyargs.is_empty()
3214 && self.vararg.is_none()
3215 && self.kwarg.is_none()
3216 }
3217
3218 pub fn iter_source_order(&self) -> ParametersSourceOrderIterator<'_> {
3226 let mut variadics = [self.vararg.as_deref(), self.kwarg.as_deref()];
3227 variadics.sort_by_key(|param| param.map_or(TextSize::new(u32::MAX), Ranged::start));
3228
3229 ParametersSourceOrderIterator {
3230 next_non_variadic_peeked: None,
3231 posonlyargs: self.posonlyargs.iter(),
3232 args: self.args.iter(),
3233 kwonlyargs: self.kwonlyargs.iter(),
3234 variadics,
3235 next_variadic: 0,
3236 }
3237 }
3238}
3239
3240pub struct ParametersIterator<'a> {
3241 posonlyargs: Iter<'a, ParameterWithDefault>,
3242 args: Iter<'a, ParameterWithDefault>,
3243 vararg: Option<&'a Parameter>,
3244 kwonlyargs: Iter<'a, ParameterWithDefault>,
3245 kwarg: Option<&'a Parameter>,
3246}
3247
3248impl<'a> ParametersIterator<'a> {
3249 fn new(parameters: &'a Parameters) -> Self {
3250 let Parameters {
3251 range: _,
3252 node_index: _,
3253 posonlyargs,
3254 args,
3255 vararg,
3256 kwonlyargs,
3257 kwarg,
3258 } = parameters;
3259 Self {
3260 posonlyargs: posonlyargs.iter(),
3261 args: args.iter(),
3262 vararg: vararg.as_deref(),
3263 kwonlyargs: kwonlyargs.iter(),
3264 kwarg: kwarg.as_deref(),
3265 }
3266 }
3267}
3268
3269impl<'a> Iterator for ParametersIterator<'a> {
3270 type Item = AnyParameterRef<'a>;
3271
3272 fn next(&mut self) -> Option<Self::Item> {
3273 let ParametersIterator {
3274 posonlyargs,
3275 args,
3276 vararg,
3277 kwonlyargs,
3278 kwarg,
3279 } = self;
3280
3281 if let Some(param) = posonlyargs.next() {
3282 return Some(AnyParameterRef::NonVariadic(param));
3283 }
3284 if let Some(param) = args.next() {
3285 return Some(AnyParameterRef::NonVariadic(param));
3286 }
3287 if let Some(param) = vararg.take() {
3288 return Some(AnyParameterRef::Variadic(param));
3289 }
3290 if let Some(param) = kwonlyargs.next() {
3291 return Some(AnyParameterRef::NonVariadic(param));
3292 }
3293 kwarg.take().map(AnyParameterRef::Variadic)
3294 }
3295
3296 fn size_hint(&self) -> (usize, Option<usize>) {
3297 let ParametersIterator {
3298 posonlyargs,
3299 args,
3300 vararg,
3301 kwonlyargs,
3302 kwarg,
3303 } = self;
3304
3305 let posonlyargs_len = posonlyargs.len();
3306 let args_len = args.len();
3307 let vararg_len = usize::from(vararg.is_some());
3308 let kwonlyargs_len = kwonlyargs.len();
3309 let kwarg_len = usize::from(kwarg.is_some());
3310
3311 let lower = posonlyargs_len
3312 .saturating_add(args_len)
3313 .saturating_add(vararg_len)
3314 .saturating_add(kwonlyargs_len)
3315 .saturating_add(kwarg_len);
3316
3317 let upper = posonlyargs_len
3318 .checked_add(args_len)
3319 .and_then(|length| length.checked_add(vararg_len))
3320 .and_then(|length| length.checked_add(kwonlyargs_len))
3321 .and_then(|length| length.checked_add(kwarg_len));
3322
3323 (lower, upper)
3324 }
3325
3326 fn last(mut self) -> Option<Self::Item> {
3327 self.next_back()
3328 }
3329}
3330
3331impl DoubleEndedIterator for ParametersIterator<'_> {
3332 fn next_back(&mut self) -> Option<Self::Item> {
3333 let ParametersIterator {
3334 posonlyargs,
3335 args,
3336 vararg,
3337 kwonlyargs,
3338 kwarg,
3339 } = self;
3340
3341 if let Some(param) = kwarg.take() {
3342 return Some(AnyParameterRef::Variadic(param));
3343 }
3344 if let Some(param) = kwonlyargs.next_back() {
3345 return Some(AnyParameterRef::NonVariadic(param));
3346 }
3347 if let Some(param) = vararg.take() {
3348 return Some(AnyParameterRef::Variadic(param));
3349 }
3350 if let Some(param) = args.next_back() {
3351 return Some(AnyParameterRef::NonVariadic(param));
3352 }
3353 posonlyargs.next_back().map(AnyParameterRef::NonVariadic)
3354 }
3355}
3356
3357impl FusedIterator for ParametersIterator<'_> {}
3358
3359impl ExactSizeIterator for ParametersIterator<'_> {}
3362
3363impl<'a> IntoIterator for &'a Parameters {
3364 type IntoIter = ParametersIterator<'a>;
3365 type Item = AnyParameterRef<'a>;
3366 fn into_iter(self) -> Self::IntoIter {
3367 self.iter()
3368 }
3369}
3370
3371impl<'a> IntoIterator for &'a Box<Parameters> {
3372 type IntoIter = ParametersIterator<'a>;
3373 type Item = AnyParameterRef<'a>;
3374 fn into_iter(self) -> Self::IntoIter {
3375 (&**self).into_iter()
3376 }
3377}
3378
3379pub struct ParametersSourceOrderIterator<'a> {
3381 next_non_variadic_peeked: Option<&'a ParameterWithDefault>,
3382 posonlyargs: Iter<'a, ParameterWithDefault>,
3383 args: Iter<'a, ParameterWithDefault>,
3384 kwonlyargs: Iter<'a, ParameterWithDefault>,
3385 variadics: [Option<&'a Parameter>; 2],
3386 next_variadic: usize,
3387}
3388
3389impl<'a> ParametersSourceOrderIterator<'a> {
3390 fn next_variadic_before(&mut self, before: TextSize) -> Option<&'a Parameter> {
3392 let param = self.variadics.get(self.next_variadic).copied().flatten()?;
3393 if param.start() < before {
3394 self.next_variadic += 1;
3395 Some(param)
3396 } else {
3397 None
3398 }
3399 }
3400
3401 fn next_non_variadic(&mut self) -> Option<&'a ParameterWithDefault> {
3402 self.next_non_variadic_peeked
3403 .take()
3404 .or_else(|| self.posonlyargs.next())
3405 .or_else(|| self.args.next())
3406 .or_else(|| self.kwonlyargs.next())
3407 }
3408
3409 fn peek_next_non_variadic(&mut self) -> Option<&'a ParameterWithDefault> {
3410 let next = self.next_non_variadic()?;
3411 self.next_non_variadic_peeked = Some(next);
3412 Some(next)
3413 }
3414}
3415
3416impl<'a> Iterator for ParametersSourceOrderIterator<'a> {
3417 type Item = AnyParameterRef<'a>;
3418
3419 fn next(&mut self) -> Option<Self::Item> {
3420 let next_non_variadic_start = self
3423 .peek_next_non_variadic()
3424 .map_or(TextSize::new(u32::MAX), Ranged::start);
3425
3426 if let Some(variadic) = self.next_variadic_before(next_non_variadic_start) {
3427 return Some(AnyParameterRef::Variadic(variadic));
3428 }
3429
3430 if let Some(non_variadic) = self.next_non_variadic() {
3431 return Some(AnyParameterRef::NonVariadic(non_variadic));
3432 }
3433
3434 self.next_variadic_before(TextSize::new(u32::MAX))
3436 .map(AnyParameterRef::Variadic)
3437 }
3438}
3439
3440impl FusedIterator for ParametersSourceOrderIterator<'_> {}
3441
3442#[derive(Clone, Debug, PartialEq)]
3447#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
3448pub struct ParameterWithDefault {
3449 pub range: TextRange,
3450 pub node_index: AtomicNodeIndex,
3451 pub parameter: Parameter,
3452 pub default: Option<Box<Expr>>,
3453}
3454
3455impl ParameterWithDefault {
3456 pub fn default(&self) -> Option<&Expr> {
3457 self.default.as_deref()
3458 }
3459
3460 pub const fn name(&self) -> &Identifier {
3461 self.parameter.name()
3462 }
3463
3464 pub fn annotation(&self) -> Option<&Expr> {
3465 self.parameter.annotation()
3466 }
3467
3468 pub fn uses_pep_484_positional_only_convention(&self) -> bool {
3472 let name = self.name();
3473 name.starts_with("__") && !name.ends_with("__")
3474 }
3475}
3476
3477#[derive(Clone, Debug, PartialEq)]
3500#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
3501pub struct Arguments {
3502 pub range: TextRange,
3503 pub node_index: AtomicNodeIndex,
3504 pub args: Box<[Expr]>,
3505 pub keywords: ThinVec<Keyword>,
3506}
3507
3508#[derive(Copy, Clone, Debug, PartialEq)]
3510pub enum ArgOrKeyword<'a> {
3511 Arg(&'a Expr),
3512 Keyword(&'a Keyword),
3513}
3514
3515impl<'a> ArgOrKeyword<'a> {
3516 pub const fn value(self) -> &'a Expr {
3517 match self {
3518 ArgOrKeyword::Arg(argument) => argument,
3519 ArgOrKeyword::Keyword(keyword) => &keyword.value,
3520 }
3521 }
3522
3523 pub const fn is_variadic(self) -> bool {
3524 match self {
3525 ArgOrKeyword::Arg(expr) => expr.is_starred_expr(),
3526 ArgOrKeyword::Keyword(keyword) => keyword.arg.is_none(),
3527 }
3528 }
3529
3530 pub const fn as_variadic(self) -> Option<&'a Keyword> {
3531 match self {
3532 ArgOrKeyword::Keyword(keyword) if keyword.arg.is_none() => Some(keyword),
3533 _ => None,
3534 }
3535 }
3536
3537 pub const fn as_keyword(self) -> Option<&'a Keyword> {
3538 match self {
3539 ArgOrKeyword::Keyword(keyword) => Some(keyword),
3540 ArgOrKeyword::Arg(_) => None,
3541 }
3542 }
3543}
3544
3545impl<'a> From<&'a Expr> for ArgOrKeyword<'a> {
3546 fn from(arg: &'a Expr) -> Self {
3547 Self::Arg(arg)
3548 }
3549}
3550
3551impl<'a> From<&'a Keyword> for ArgOrKeyword<'a> {
3552 fn from(keyword: &'a Keyword) -> Self {
3553 Self::Keyword(keyword)
3554 }
3555}
3556
3557impl Ranged for ArgOrKeyword<'_> {
3558 fn range(&self) -> TextRange {
3559 match self {
3560 Self::Arg(arg) => arg.range(),
3561 Self::Keyword(keyword) => keyword.range(),
3562 }
3563 }
3564}
3565
3566impl Arguments {
3567 pub fn len(&self) -> usize {
3569 self.args.len() + self.keywords.len()
3570 }
3571
3572 pub fn is_empty(&self) -> bool {
3574 self.len() == 0
3575 }
3576
3577 pub fn find_keyword(&self, keyword_name: &str) -> Option<&Keyword> {
3579 self.keywords.iter().find(|keyword| {
3580 let Keyword { arg, .. } = keyword;
3581 arg.as_ref().is_some_and(|arg| arg == keyword_name)
3582 })
3583 }
3584
3585 pub fn find_positional(&self, position: usize) -> Option<&Expr> {
3587 self.args
3588 .iter()
3589 .take_while(|expr| !expr.is_starred_expr())
3590 .nth(position)
3591 }
3592
3593 pub fn find_argument_value(&self, name: &str, position: usize) -> Option<&Expr> {
3597 self.find_argument(name, position).map(ArgOrKeyword::value)
3598 }
3599
3600 pub fn find_argument(&self, name: &str, position: usize) -> Option<ArgOrKeyword<'_>> {
3604 self.find_keyword(name)
3605 .map(ArgOrKeyword::from)
3606 .or_else(|| self.find_positional(position).map(ArgOrKeyword::from))
3607 }
3608
3609 pub fn iter_source_order(&self) -> ArgumentsSourceOrder<'_> {
3644 ArgumentsSourceOrder {
3645 args: &self.args,
3646 keywords: &self.keywords,
3647 next_arg: 0,
3648 next_keyword: 0,
3649 }
3650 }
3651
3652 pub fn inner_range(&self) -> TextRange {
3653 TextRange::new(self.l_paren_range().end(), self.r_paren_range().start())
3654 }
3655
3656 pub fn l_paren_range(&self) -> TextRange {
3657 TextRange::at(self.start(), '('.text_len())
3658 }
3659
3660 pub fn r_paren_range(&self) -> TextRange {
3661 TextRange::new(self.end() - ')'.text_len(), self.end())
3662 }
3663}
3664
3665#[derive(Clone)]
3667pub struct ArgumentsSourceOrder<'a> {
3668 args: &'a [Expr],
3669 keywords: &'a [Keyword],
3670 next_arg: usize,
3671 next_keyword: usize,
3672}
3673
3674impl<'a> Iterator for ArgumentsSourceOrder<'a> {
3675 type Item = ArgOrKeyword<'a>;
3676
3677 fn next(&mut self) -> Option<Self::Item> {
3678 let arg = self.args.get(self.next_arg);
3679 let keyword = self.keywords.get(self.next_keyword);
3680
3681 if let Some(arg) = arg
3682 && keyword.is_none_or(|keyword| arg.start() <= keyword.start())
3683 {
3684 self.next_arg += 1;
3685 Some(ArgOrKeyword::Arg(arg))
3686 } else if let Some(keyword) = keyword {
3687 self.next_keyword += 1;
3688 Some(ArgOrKeyword::Keyword(keyword))
3689 } else {
3690 None
3691 }
3692 }
3693}
3694
3695impl FusedIterator for ArgumentsSourceOrder<'_> {}
3696
3697#[derive(Clone, Debug, PartialEq)]
3707#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
3708pub struct TypeParams {
3709 pub range: TextRange,
3710 pub node_index: AtomicNodeIndex,
3711 pub type_params: Vec<TypeParam>,
3712}
3713
3714impl Deref for TypeParams {
3715 type Target = [TypeParam];
3716
3717 fn deref(&self) -> &Self::Target {
3718 &self.type_params
3719 }
3720}
3721
3722impl<'a> IntoIterator for &'a TypeParams {
3723 type Item = &'a TypeParam;
3724 type IntoIter = std::slice::Iter<'a, TypeParam>;
3725
3726 fn into_iter(self) -> Self::IntoIter {
3727 self.type_params.iter()
3728 }
3729}
3730
3731pub type Suite = ThinVec<Stmt>;
3735
3736pub type DecoratorList = ThinVec<Decorator>;
3737
3738pub type Patterns = ThinVec<Pattern>;
3739
3740pub type PatternKeys = ThinVec<Expr>;
3741
3742pub type ParameterWithDefaults = ThinVec<ParameterWithDefault>;
3743
3744#[derive(PartialEq, Eq, Debug, Clone, Hash, Copy)]
3748#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
3749pub enum IpyEscapeKind {
3750 Shell,
3752 ShCap,
3754 Help,
3756 Help2,
3758 Magic,
3760 Magic2,
3762 Quote,
3765 Quote2,
3767 Paren,
3769}
3770
3771impl TryFrom<char> for IpyEscapeKind {
3772 type Error = String;
3773
3774 fn try_from(ch: char) -> Result<Self, Self::Error> {
3775 match ch {
3776 '!' => Ok(IpyEscapeKind::Shell),
3777 '?' => Ok(IpyEscapeKind::Help),
3778 '%' => Ok(IpyEscapeKind::Magic),
3779 ',' => Ok(IpyEscapeKind::Quote),
3780 ';' => Ok(IpyEscapeKind::Quote2),
3781 '/' => Ok(IpyEscapeKind::Paren),
3782 _ => Err(format!("Unexpected magic escape: {ch}")),
3783 }
3784 }
3785}
3786
3787impl TryFrom<[char; 2]> for IpyEscapeKind {
3788 type Error = String;
3789
3790 fn try_from(ch: [char; 2]) -> Result<Self, Self::Error> {
3791 match ch {
3792 ['!', '!'] => Ok(IpyEscapeKind::ShCap),
3793 ['?', '?'] => Ok(IpyEscapeKind::Help2),
3794 ['%', '%'] => Ok(IpyEscapeKind::Magic2),
3795 [c1, c2] => Err(format!("Unexpected magic escape: {c1}{c2}")),
3796 }
3797 }
3798}
3799
3800impl fmt::Display for IpyEscapeKind {
3801 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3802 f.write_str(self.as_str())
3803 }
3804}
3805
3806impl IpyEscapeKind {
3807 pub const fn is_help(self) -> bool {
3809 matches!(self, IpyEscapeKind::Help | IpyEscapeKind::Help2)
3810 }
3811
3812 pub const fn is_magic(self) -> bool {
3814 matches!(self, IpyEscapeKind::Magic | IpyEscapeKind::Magic2)
3815 }
3816
3817 pub fn as_str(self) -> &'static str {
3818 match self {
3819 IpyEscapeKind::Shell => "!",
3820 IpyEscapeKind::ShCap => "!!",
3821 IpyEscapeKind::Help => "?",
3822 IpyEscapeKind::Help2 => "??",
3823 IpyEscapeKind::Magic => "%",
3824 IpyEscapeKind::Magic2 => "%%",
3825 IpyEscapeKind::Quote => ",",
3826 IpyEscapeKind::Quote2 => ";",
3827 IpyEscapeKind::Paren => "/",
3828 }
3829 }
3830}
3831
3832#[derive(Clone, Debug, PartialEq, Eq, Hash)]
3840#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
3841pub struct Identifier {
3842 pub id: Name,
3843 pub range: TextRange,
3844 pub node_index: AtomicNodeIndex,
3845}
3846
3847impl Identifier {
3848 #[inline]
3849 pub fn new(id: impl Into<Name>, range: TextRange) -> Self {
3850 Self {
3851 id: id.into(),
3852 node_index: AtomicNodeIndex::NONE,
3853 range,
3854 }
3855 }
3856
3857 pub fn id(&self) -> &Name {
3858 &self.id
3859 }
3860
3861 pub fn is_valid(&self) -> bool {
3862 !self.id.is_empty()
3863 }
3864}
3865
3866impl Identifier {
3867 #[inline]
3868 pub fn as_str(&self) -> &str {
3869 self.id.as_str()
3870 }
3871}
3872
3873impl PartialEq<str> for Identifier {
3874 #[inline]
3875 fn eq(&self, other: &str) -> bool {
3876 self.id == other
3877 }
3878}
3879
3880impl PartialEq<String> for Identifier {
3881 #[inline]
3882 fn eq(&self, other: &String) -> bool {
3883 self.id == other
3884 }
3885}
3886
3887impl std::ops::Deref for Identifier {
3888 type Target = str;
3889 #[inline]
3890 fn deref(&self) -> &Self::Target {
3891 self.id.as_str()
3892 }
3893}
3894
3895impl AsRef<str> for Identifier {
3896 #[inline]
3897 fn as_ref(&self) -> &str {
3898 self.id.as_str()
3899 }
3900}
3901
3902impl std::fmt::Display for Identifier {
3903 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3904 std::fmt::Display::fmt(&self.id, f)
3905 }
3906}
3907
3908impl From<Identifier> for Name {
3909 #[inline]
3910 fn from(identifier: Identifier) -> Name {
3911 identifier.id
3912 }
3913}
3914
3915#[derive(Clone, Copy, Debug, Hash, PartialEq)]
3916#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
3917pub enum Singleton {
3918 None,
3919 True,
3920 False,
3921}
3922
3923impl From<bool> for Singleton {
3924 fn from(value: bool) -> Self {
3925 if value {
3926 Singleton::True
3927 } else {
3928 Singleton::False
3929 }
3930 }
3931}
3932
3933#[cfg(test)]
3934mod tests {
3935 use crate::generated::*;
3936 use crate::{Arguments, Mod, Parameters};
3937
3938 #[test]
3939 #[cfg(target_pointer_width = "64")]
3940 fn size() {
3941 assert_eq!(std::mem::size_of::<Stmt>(), 88);
3942 assert_eq!(std::mem::size_of::<StmtFunctionDef>(), 88);
3943 assert_eq!(std::mem::size_of::<StmtClassDef>(), 80);
3944 assert_eq!(std::mem::size_of::<StmtTry>(), 64);
3945 assert_eq!(std::mem::size_of::<Mod>(), 32);
3946 assert_eq!(std::mem::size_of::<Pattern>(), 72);
3947 assert_eq!(std::mem::size_of::<Parameters>(), 56);
3948 assert_eq!(std::mem::size_of::<Arguments>(), 40);
3949 assert_eq!(std::mem::size_of::<Expr>(), 64);
3950 assert_eq!(std::mem::size_of::<ExprAttribute>(), 56);
3951 assert_eq!(std::mem::size_of::<ExprAwait>(), 24);
3952 assert_eq!(std::mem::size_of::<ExprBinOp>(), 32);
3953 assert_eq!(std::mem::size_of::<ExprBoolOp>(), 40);
3954 assert_eq!(std::mem::size_of::<ExprBooleanLiteral>(), 16);
3955 assert_eq!(std::mem::size_of::<ExprBytesLiteral>(), 48);
3956 assert_eq!(std::mem::size_of::<ExprCall>(), 56);
3957 assert_eq!(std::mem::size_of::<ExprCompare>(), 56);
3958 assert_eq!(std::mem::size_of::<ExprDict>(), 40);
3959 assert_eq!(std::mem::size_of::<ExprDictComp>(), 56);
3960 assert_eq!(std::mem::size_of::<ExprEllipsisLiteral>(), 12);
3961 assert_eq!(std::mem::size_of::<ExprFString>(), 56);
3962 assert_eq!(std::mem::size_of::<ExprGenerator>(), 48);
3963 assert_eq!(std::mem::size_of::<ExprIf>(), 40);
3964 assert_eq!(std::mem::size_of::<ExprIpyEscapeCommand>(), 32);
3965 assert_eq!(std::mem::size_of::<ExprLambda>(), 32);
3966 assert_eq!(std::mem::size_of::<ExprList>(), 40);
3967 assert_eq!(std::mem::size_of::<ExprListComp>(), 48);
3968 assert_eq!(std::mem::size_of::<ExprName>(), 32);
3969 assert_eq!(std::mem::size_of::<ExprNamed>(), 32);
3970 assert_eq!(std::mem::size_of::<ExprNoneLiteral>(), 12);
3971 assert_eq!(std::mem::size_of::<ExprNumberLiteral>(), 40);
3972 assert_eq!(std::mem::size_of::<ExprSet>(), 40);
3973 assert_eq!(std::mem::size_of::<ExprSetComp>(), 48);
3974 assert_eq!(std::mem::size_of::<ExprSlice>(), 40);
3975 assert_eq!(std::mem::size_of::<ExprStarred>(), 24);
3976 assert_eq!(std::mem::size_of::<ExprStringLiteral>(), 48);
3977 assert_eq!(std::mem::size_of::<ExprSubscript>(), 32);
3978 assert_eq!(std::mem::size_of::<ExprTuple>(), 40);
3979 assert_eq!(std::mem::size_of::<ExprUnaryOp>(), 24);
3980 assert_eq!(std::mem::size_of::<ExprYield>(), 24);
3981 assert_eq!(std::mem::size_of::<ExprYieldFrom>(), 24);
3982 }
3983}