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 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
1331#[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 pub fn single(string: StringLiteral) -> Self {
1341 Self {
1342 inner: StringLiteralValueInner::Single(string),
1343 }
1344 }
1345
1346 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 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 pub const fn is_implicit_concatenated(&self) -> bool {
1380 matches!(self.inner, StringLiteralValueInner::Concatenated(_))
1381 }
1382
1383 pub fn is_unicode(&self) -> bool {
1392 self.iter()
1393 .next()
1394 .is_some_and(|part| part.flags.prefix().is_unicode())
1395 }
1396
1397 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 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 pub fn iter(&self) -> Iter<'_, StringLiteral> {
1415 self.as_slice().iter()
1416 }
1417
1418 pub fn iter_mut(&mut self) -> IterMut<'_, StringLiteral> {
1421 self.as_mut_slice().iter_mut()
1422 }
1423
1424 pub fn is_empty(&self) -> bool {
1430 self.len() == 0
1431 }
1432
1433 pub fn len(&self) -> usize {
1436 self.iter().fold(0, |acc, part| acc + part.value.len())
1437 }
1438
1439 pub fn chars(&self) -> impl Iterator<Item = char> + Clone + '_ {
1441 self.iter().flat_map(|part| part.value.chars())
1442 }
1443
1444 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 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#[derive(Clone, Debug, PartialEq)]
1491#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1492enum StringLiteralValueInner {
1493 Single(StringLiteral),
1495
1496 Concatenated(ConcatenatedStringLiteral),
1498}
1499
1500bitflags! {
1501 #[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
1502 struct StringLiteralFlagsInner: u8 {
1503 const DOUBLE = 1 << 0;
1506
1507 const TRIPLE_QUOTED = 1 << 1;
1510
1511 const U_PREFIX = 1 << 2;
1517
1518 const R_PREFIX_LOWER = 1 << 3;
1522
1523 const R_PREFIX_UPPER = 1 << 4;
1529
1530 const INVALID = 1 << 5;
1532
1533 const UNCLOSED = 1 << 6;
1535 }
1536}
1537
1538#[cfg(feature = "get-size")]
1539impl get_size2::GetSize for StringLiteralFlagsInner {}
1540
1541#[derive(Copy, Clone, Eq, PartialEq, Hash)]
1554#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1555pub struct StringLiteralFlags(StringLiteralFlagsInner);
1556
1557impl StringLiteralFlags {
1558 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 fn quote_style(self) -> Quote {
1653 if self.0.contains(StringLiteralFlagsInner::DOUBLE) {
1654 Quote::Double
1655 } else {
1656 Quote::Single
1657 }
1658 }
1659
1660 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#[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 pub fn as_str(&self) -> &str {
1713 self
1714 }
1715
1716 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 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#[derive(Clone)]
1751#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1752struct ConcatenatedStringLiteral {
1753 strings: Vec<StringLiteral>,
1755 value: OnceLock<Box<str>>,
1757}
1758
1759impl ConcatenatedStringLiteral {
1760 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 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 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#[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 pub fn single(value: BytesLiteral) -> Self {
1812 Self {
1813 inner: BytesLiteralValueInner::Single(value),
1814 }
1815 }
1816
1817 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 pub const fn is_implicit_concatenated(&self) -> bool {
1836 matches!(self.inner, BytesLiteralValueInner::Concatenated(_))
1837 }
1838
1839 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 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 pub fn iter(&self) -> Iter<'_, BytesLiteral> {
1857 self.as_slice().iter()
1858 }
1859
1860 pub fn iter_mut(&mut self) -> IterMut<'_, BytesLiteral> {
1863 self.as_mut_slice().iter_mut()
1864 }
1865
1866 pub fn is_empty(&self) -> bool {
1872 self.iter().all(|part| part.is_empty())
1873 }
1874
1875 pub fn len(&self) -> usize {
1877 self.iter().map(|part| part.len()).sum()
1878 }
1879
1880 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 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#[derive(Clone, Debug, PartialEq)]
1933#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1934enum BytesLiteralValueInner {
1935 Single(BytesLiteral),
1937
1938 Concatenated(Vec<BytesLiteral>),
1940}
1941
1942bitflags! {
1943 #[derive(Default, Copy, Clone, PartialEq, Eq, Hash)]
1944 struct BytesLiteralFlagsInner: u8 {
1945 const DOUBLE = 1 << 0;
1948
1949 const TRIPLE_QUOTED = 1 << 1;
1952
1953 const R_PREFIX_LOWER = 1 << 2;
1956
1957 const R_PREFIX_UPPER = 1 << 3;
1962
1963 const INVALID = 1 << 4;
1965
1966 const UNCLOSED = 1 << 5;
1968 }
1969}
1970
1971#[cfg(feature = "get-size")]
1972impl get_size2::GetSize for BytesLiteralFlagsInner {}
1973
1974#[derive(Copy, Clone, Eq, PartialEq, Hash)]
1986#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
1987pub struct BytesLiteralFlags(BytesLiteralFlagsInner);
1988
1989impl BytesLiteralFlags {
1990 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 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 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#[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 pub fn as_slice(&self) -> &[u8] {
2126 self
2127 }
2128
2129 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 #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
2161 struct AnyStringFlagsInner: u16 {
2162 const DOUBLE = 1 << 0;
2165
2166 const TRIPLE_QUOTED = 1 << 1;
2169
2170 const U_PREFIX = 1 << 2;
2174
2175 const B_PREFIX = 1 << 3;
2181
2182 const F_PREFIX = 1 << 4;
2186
2187 const T_PREFIX = 1 << 5;
2191
2192 const R_PREFIX_LOWER = 1 << 6;
2197
2198 const R_PREFIX_UPPER = 1 << 7;
2204
2205 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 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 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 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 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 pub const fn is_u_string(self) -> bool {
2266 self.0.contains(AnyStringFlagsInner::U_PREFIX)
2267 }
2268
2269 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 pub const fn is_interpolated_string(self) -> bool {
2278 self.0
2279 .intersects(AnyStringFlagsInner::F_PREFIX.union(AnyStringFlagsInner::T_PREFIX))
2280 }
2281
2282 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 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 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 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 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 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 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#[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#[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#[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 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 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 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#[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#[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#[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#[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#[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#[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#[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#[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#[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 pub fn is_irrefutable(&self) -> bool {
2854 self.irrefutable_pattern().is_some()
2855 }
2856
2857 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 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#[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#[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 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#[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#[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#[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#[derive(Debug, PartialEq, Clone, Copy)]
3030pub enum AnyParameterRef<'a> {
3031 Variadic(&'a Parameter),
3038
3039 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) => ¶m.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#[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 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 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 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 pub fn iter(&self) -> ParametersIterator<'_> {
3133 ParametersIterator::new(self)
3134 }
3135
3136 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 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 pub fn includes(&self, name: &str) -> bool {
3164 self.iter().any(|param| param.name() == name)
3165 }
3166
3167 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 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
3317impl 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
3337pub 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 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 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 self.next_variadic_before(TextSize::new(u32::MAX))
3394 .map(AnyParameterRef::Variadic)
3395 }
3396}
3397
3398impl FusedIterator for ParametersSourceOrderIterator<'_> {}
3399
3400#[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 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#[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#[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 pub fn len(&self) -> usize {
3527 self.args.len() + self.keywords.len()
3528 }
3529
3530 pub fn is_empty(&self) -> bool {
3532 self.len() == 0
3533 }
3534
3535 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 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 pub fn find_argument_value(&self, name: &str, position: usize) -> Option<&Expr> {
3555 self.find_argument(name, position).map(ArgOrKeyword::value)
3556 }
3557
3558 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 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#[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#[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
3689pub 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#[derive(PartialEq, Eq, Debug, Clone, Hash, Copy)]
3706#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]
3707pub enum IpyEscapeKind {
3708 Shell,
3710 ShCap,
3712 Help,
3714 Help2,
3716 Magic,
3718 Magic2,
3720 Quote,
3723 Quote2,
3725 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 pub const fn is_help(self) -> bool {
3767 matches!(self, IpyEscapeKind::Help | IpyEscapeKind::Help2)
3768 }
3769
3770 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#[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}