rustpython_ast/
builtin.rs

1//! `builtin_types` in asdl.py and Attributed
2
3use crate::bigint::BigInt;
4
5pub type String = std::string::String;
6
7#[derive(Clone, Debug, PartialEq, Eq, Hash)]
8pub struct Identifier(String);
9
10impl Identifier {
11    #[inline]
12    pub fn new(s: impl Into<String>) -> Self {
13        Self(s.into())
14    }
15}
16
17impl Identifier {
18    #[inline]
19    pub fn as_str(&self) -> &str {
20        self.0.as_str()
21    }
22}
23
24impl std::cmp::PartialEq<str> for Identifier {
25    #[inline]
26    fn eq(&self, other: &str) -> bool {
27        self.0 == other
28    }
29}
30
31impl std::cmp::PartialEq<String> for Identifier {
32    #[inline]
33    fn eq(&self, other: &String) -> bool {
34        &self.0 == other
35    }
36}
37
38impl std::ops::Deref for Identifier {
39    type Target = str;
40    #[inline]
41    fn deref(&self) -> &Self::Target {
42        self.0.as_str()
43    }
44}
45
46impl AsRef<str> for Identifier {
47    #[inline]
48    fn as_ref(&self) -> &str {
49        self.0.as_str()
50    }
51}
52
53impl AsRef<String> for Identifier {
54    #[inline]
55    fn as_ref(&self) -> &String {
56        &self.0
57    }
58}
59
60impl std::fmt::Display for Identifier {
61    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62        self.0.fmt(f)
63    }
64}
65
66impl From<Identifier> for String {
67    #[inline]
68    fn from(id: Identifier) -> String {
69        id.0
70    }
71}
72
73impl From<String> for Identifier {
74    #[inline]
75    fn from(id: String) -> Self {
76        Self(id)
77    }
78}
79
80impl<'a> From<&'a str> for Identifier {
81    #[inline]
82    fn from(id: &'a str) -> Identifier {
83        id.to_owned().into()
84    }
85}
86
87#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
88pub struct Int(u32);
89
90impl Int {
91    pub fn new(i: u32) -> Self {
92        Self(i)
93    }
94    pub fn to_u32(&self) -> u32 {
95        self.0
96    }
97    pub fn to_usize(&self) -> usize {
98        self.0 as _
99    }
100}
101
102impl std::cmp::PartialEq<u32> for Int {
103    #[inline]
104    fn eq(&self, other: &u32) -> bool {
105        self.0 == *other
106    }
107}
108
109impl std::cmp::PartialEq<usize> for Int {
110    #[inline]
111    fn eq(&self, other: &usize) -> bool {
112        self.0 as usize == *other
113    }
114}
115
116#[derive(Clone, Debug, PartialEq, is_macro::Is)]
117pub enum Constant {
118    None,
119    Bool(bool),
120    Str(String),
121    Bytes(Vec<u8>),
122    Int(BigInt),
123    Tuple(Vec<Constant>),
124    Float(f64),
125    Complex { real: f64, imag: f64 },
126    Ellipsis,
127}
128
129impl Constant {
130    pub fn is_true(self) -> bool {
131        self.bool().map_or(false, |b| b)
132    }
133    pub fn is_false(self) -> bool {
134        self.bool().map_or(false, |b| !b)
135    }
136    pub fn complex(self) -> Option<(f64, f64)> {
137        match self {
138            Constant::Complex { real, imag } => Some((real, imag)),
139            _ => None,
140        }
141    }
142}
143
144impl From<String> for Constant {
145    fn from(s: String) -> Constant {
146        Self::Str(s)
147    }
148}
149impl From<Vec<u8>> for Constant {
150    fn from(b: Vec<u8>) -> Constant {
151        Self::Bytes(b)
152    }
153}
154impl From<bool> for Constant {
155    fn from(b: bool) -> Constant {
156        Self::Bool(b)
157    }
158}
159impl From<BigInt> for Constant {
160    fn from(i: BigInt) -> Constant {
161        Self::Int(i)
162    }
163}
164
165#[cfg(feature = "rustpython-literal")]
166impl std::fmt::Display for Constant {
167    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
168        match self {
169            Constant::None => f.pad("None"),
170            Constant::Bool(b) => f.pad(if *b { "True" } else { "False" }),
171            Constant::Str(s) => rustpython_literal::escape::UnicodeEscape::new_repr(s.as_str())
172                .str_repr()
173                .write(f),
174            Constant::Bytes(b) => {
175                let escape = rustpython_literal::escape::AsciiEscape::new_repr(b);
176                let repr = escape.bytes_repr().to_string().unwrap();
177                f.pad(&repr)
178            }
179            Constant::Int(i) => i.fmt(f),
180            Constant::Tuple(tup) => {
181                if let [elt] = &**tup {
182                    write!(f, "({elt},)")
183                } else {
184                    f.write_str("(")?;
185                    for (i, elt) in tup.iter().enumerate() {
186                        if i != 0 {
187                            f.write_str(", ")?;
188                        }
189                        elt.fmt(f)?;
190                    }
191                    f.write_str(")")
192                }
193            }
194            Constant::Float(fp) => f.pad(&rustpython_literal::float::to_string(*fp)),
195            Constant::Complex { real, imag } => {
196                if *real == 0.0 {
197                    write!(f, "{imag}j")
198                } else {
199                    write!(f, "({real}{imag:+}j)")
200                }
201            }
202            Constant::Ellipsis => f.pad("..."),
203        }
204    }
205}
206
207#[cfg(test)]
208mod tests {
209    use super::*;
210    #[test]
211    fn test_is_macro() {
212        let none = Constant::None;
213        assert!(none.is_none());
214        assert!(!none.is_bool());
215    }
216}