s_expr/
data.rs

1/// Type of group
2#[derive(Clone, Copy, Debug, PartialEq, Eq)]
3#[repr(u8)]
4pub enum GroupKind {
5    /// Group of ()
6    Paren,
7    /// Group of {}
8    Brace,
9    /// Group of []
10    Bracket,
11}
12
13/// Atom literal (Number, Bytes, String, or Ident)
14#[derive(Clone, Debug)]
15pub enum Atom<'a> {
16    /// Integral number literal
17    Integral(ANum<'a>),
18    /// Decimal number literal (e.g. `12.34`)
19    Decimal(ADecimal<'a>),
20    /// Bytes literal
21    Bytes(ABytes<'a>),
22    /// String literal
23    String(AStr<'a>),
24    /// Ident
25    Ident(&'a str),
26}
27
28impl<'a> Atom<'a> {
29    /// Get the Number in an Atom if the right variant, or None
30    pub fn number(&self) -> Option<&ANum<'a>> {
31        match self {
32            Atom::Integral(num) => Some(num),
33            _ => None,
34        }
35    }
36
37    /// Get the Decimal in an Atom if the right variant, or None
38    pub fn decimal(&self) -> Option<&ADecimal<'a>> {
39        match self {
40            Atom::Decimal(dec) => Some(dec),
41            _ => None,
42        }
43    }
44
45    /// Get the Bytes in an Atom if the right variant, or None
46    pub fn bytes(&self) -> Option<&ABytes<'a>> {
47        match self {
48            Atom::Bytes(bytes) => Some(bytes),
49            _ => None,
50        }
51    }
52
53    /// Get the String in an Atom if the right variant, or None
54    pub fn string(&self) -> Option<&AStr<'a>> {
55        match self {
56            Atom::String(str) => Some(str),
57            _ => None,
58        }
59    }
60
61    /// Get the Ident in an Atom if the right variant, or None
62    pub fn ident(&self) -> Option<&'a str> {
63        match self {
64            Atom::Ident(ident) => Some(ident),
65            _ => None,
66        }
67    }
68}
69
70/// A String literal, that may contains escapes
71#[derive(Clone, Debug)]
72pub struct AStr<'a> {
73    pub has_escape: bool,
74    pub raw_data: &'a str,
75}
76
77impl<'a> AStr<'a> {
78    pub fn to_string(&self) -> String {
79        self.raw_data.to_string()
80    }
81}
82
83/// A Bytes literal
84#[derive(Clone, Debug)]
85pub struct ABytes<'a>(pub &'a str);
86
87/// Supported number base
88#[derive(Copy, Clone, Debug, PartialEq, Eq)]
89pub enum ANumBase {
90    /// Binary Base (2), made of '0'..'1'
91    Binary = 2,
92    /// Decimal Base (10), made of '0'..'9'
93    Decimal = 10,
94    /// Hexadecimal Base (16), made of '0'..'9', 'a'..'f', 'A'..'F'
95    Hexadecimal = 16,
96}
97
98impl ANumBase {
99    /// Return the radix number associated with the support base
100    pub fn to_radix(self) -> u32 {
101        self as u32
102    }
103
104    pub fn from_radix(v: u32) -> Option<Self> {
105        if v == 2 {
106            Some(Self::Binary)
107        } else if v == 10 {
108            Some(Self::Decimal)
109        } else if v == 16 {
110            Some(Self::Hexadecimal)
111        } else {
112            None
113        }
114    }
115}
116
117/// Integral Number
118#[derive(Clone, Debug)]
119pub struct ANum<'a> {
120    pub base: ANumBase,
121    pub dat: &'a str,
122}
123
124impl<'a> ANum<'a> {
125    /// Get the base of the data
126    pub fn base(&self) -> ANumBase {
127        self.base
128    }
129
130    /// Get the radix of the data, which is either 2 (binary), 10 (decimal) or 16 (hexadecimal)
131    pub fn radix(&self) -> u32 {
132        self.base.to_radix()
133    }
134
135    /// Get the data associated with the number, which depending on the radix is
136    /// either binary, decimal and hexadecimal. it also might contains _ separators
137    pub fn raw_data(&self) -> &'a str {
138        self.dat
139    }
140
141    /// Get the digits associated with the number, which depending on the radix is
142    /// either binary, decimal and hexadecimal. The '_' characters are filtered away
143    pub fn digits(&self) -> String {
144        self.dat.chars().filter(|c| *c != '_').collect::<String>()
145    }
146
147    /// Try to parse the ANum into a u8, which will raise an error if there's an overflow
148    pub fn to_u8(&self) -> Result<u8, core::num::ParseIntError> {
149        u8::from_str_radix(&self.digits(), self.base.to_radix())
150    }
151
152    /// Try to parse the ANum into a u16, which will raise an error if there's an overflow
153    pub fn to_u16(&self) -> Result<u16, core::num::ParseIntError> {
154        u16::from_str_radix(&self.digits(), self.base.to_radix())
155    }
156
157    /// Try to parse the ANum into a u32, which will raise an error if there's an overflow
158    pub fn to_u32(&self) -> Result<u32, core::num::ParseIntError> {
159        u32::from_str_radix(&self.digits(), self.base.to_radix())
160    }
161
162    /// Try to parse the ANum into a u64, which will raise an error if there's an overflow
163    pub fn to_u64(&self) -> Result<u64, core::num::ParseIntError> {
164        u64::from_str_radix(&self.digits(), self.base.to_radix())
165    }
166
167    /// Try to parse the ANum into a u128, which will raise an error if there's an overflow
168    pub fn to_u128(&self) -> Result<u128, core::num::ParseIntError> {
169        u128::from_str_radix(&self.digits(), self.base.to_radix())
170    }
171}
172
173/// Decimal Number (e.g. `1.3`)
174#[derive(Clone, Debug)]
175pub struct ADecimal<'a> {
176    pub raw_integral: &'a str,
177    pub raw_fractional: &'a str,
178}
179
180impl<'a> ADecimal<'a> {
181    /// Get the data associated with the integral number. All '_' characters are filtered away
182    pub fn integral(&self) -> String {
183        self.raw_integral
184            .chars()
185            .filter(|c| *c != '_')
186            .collect::<String>()
187    }
188
189    /// Get the data associated with the fractional number. All '_' characters are filtered away
190    pub fn fractional(&self) -> String {
191        self.raw_fractional
192            .chars()
193            .filter(|c| *c != '_')
194            .collect::<String>()
195    }
196}