Skip to main content

moxy_token/lit/
mod.rs

1use crate::lex::{Cursor, LexError, Scan};
2use crate::{Span, Spanner, ToTokens, TokenStream, TokenTree};
3
4pub mod float;
5pub mod int;
6
7mod r#bool;
8mod byte;
9mod byte_str;
10mod c_str;
11mod char;
12mod str;
13mod verbatim;
14
15pub use r#bool::*;
16pub use byte::*;
17pub use byte_str::*;
18pub use c_str::*;
19pub use char::*;
20pub use float::*;
21pub use int::*;
22pub use str::*;
23pub use verbatim::*;
24
25#[derive(Debug, Clone, PartialEq, Eq, Hash)]
26#[cfg_attr(feature = "serde", derive(serde::Serialize), serde(into = "String"))]
27pub enum Lit {
28    Int(LitInt),
29    Float(LitFloat),
30    Str(LitStr),
31    ByteStr(LitByteStr),
32    CStr(LitCStr),
33    Char(LitChar),
34    Byte(LitByte),
35    Bool(LitBool),
36    Verbatim(LitVerbatim),
37}
38
39impl Lit {
40    #[inline]
41    pub fn string(value: &str) -> Self {
42        Self::Str(LitStr::new(value, Span::default()))
43    }
44
45    #[inline]
46    pub fn char(value: char) -> Self {
47        Self::Char(LitChar::new(value, Span::default()))
48    }
49
50    /// Classify and decode an arbitrary literal repr into the matching variant. Used by
51    /// the proc-macro bridges, which only have the source text. Falls back to
52    /// [`LitVerbatim`] for anything that doesn't lex as a known literal.
53    #[inline]
54    pub fn from_repr(repr: &str, span: Span) -> Self {
55        use std::str::FromStr;
56
57        match TokenStream::from_str(repr).ok().and_then(|ts| ts.into_iter().next()) {
58            Some(TokenTree::Literal(mut lit)) if lit.repr() == repr => {
59                lit.set_span(span);
60                lit
61            }
62            _ => Self::Verbatim(LitVerbatim::new(repr, span)),
63        }
64    }
65
66    #[inline]
67    pub fn is_int(&self) -> bool {
68        matches!(self, Self::Int(_))
69    }
70
71    #[inline]
72    pub fn is_float(&self) -> bool {
73        matches!(self, Self::Float(_))
74    }
75
76    #[inline]
77    pub fn is_str(&self) -> bool {
78        matches!(self, Self::Str(_))
79    }
80
81    #[inline]
82    pub fn is_c_str(&self) -> bool {
83        matches!(self, Self::CStr(_))
84    }
85
86    #[inline]
87    pub fn is_bool(&self) -> bool {
88        matches!(self, Self::Bool(_))
89    }
90
91    #[inline]
92    pub fn is_char(&self) -> bool {
93        matches!(self, Self::Char(_))
94    }
95
96    #[inline]
97    pub fn is_byte(&self) -> bool {
98        matches!(self, Self::Byte(_))
99    }
100
101    #[inline]
102    pub fn is_byte_str(&self) -> bool {
103        matches!(self, Self::ByteStr(_))
104    }
105
106    #[inline]
107    pub fn is_verbatim(&self) -> bool {
108        matches!(self, Self::Verbatim(_))
109    }
110
111    #[inline]
112    pub fn as_str(&self) -> Option<&LitStr> {
113        if let Self::Str(v) = self { Some(v) } else { None }
114    }
115
116    #[inline]
117    pub fn as_c_str(&self) -> Option<&LitCStr> {
118        if let Self::CStr(v) = self { Some(v) } else { None }
119    }
120
121    #[inline]
122    pub fn as_bool(&self) -> Option<&LitBool> {
123        if let Self::Bool(v) = self { Some(v) } else { None }
124    }
125
126    #[inline]
127    pub fn as_int(&self) -> Option<&LitInt> {
128        if let Self::Int(v) = self { Some(v) } else { None }
129    }
130
131    #[inline]
132    pub fn as_float(&self) -> Option<&LitFloat> {
133        if let Self::Float(v) = self { Some(v) } else { None }
134    }
135
136    #[inline]
137    pub fn as_char(&self) -> Option<&LitChar> {
138        if let Self::Char(v) = self { Some(v) } else { None }
139    }
140
141    #[inline]
142    pub fn as_byte(&self) -> Option<&LitByte> {
143        if let Self::Byte(v) = self { Some(v) } else { None }
144    }
145
146    #[inline]
147    pub fn as_byte_str(&self) -> Option<&LitByteStr> {
148        if let Self::ByteStr(v) = self { Some(v) } else { None }
149    }
150
151    #[inline]
152    pub fn to_token_tree(&self) -> TokenTree {
153        TokenTree::Literal(self.clone())
154    }
155
156    #[inline]
157    pub fn into_token_tree(self) -> TokenTree {
158        TokenTree::Literal(self)
159    }
160
161    #[inline]
162    pub fn repr(&self) -> &str {
163        match self {
164            Self::Int(v) => v.repr(),
165            Self::Float(v) => v.repr(),
166            Self::Str(v) => v.repr(),
167            Self::ByteStr(v) => v.repr(),
168            Self::CStr(v) => v.repr(),
169            Self::Char(v) => v.repr(),
170            Self::Byte(v) => v.repr(),
171            Self::Bool(v) => v.repr(),
172            Self::Verbatim(v) => v.repr(),
173        }
174    }
175
176    #[inline]
177    pub fn span(&self) -> Span {
178        match self {
179            Self::Int(v) => v.span(),
180            Self::Float(v) => v.span(),
181            Self::Str(v) => v.span(),
182            Self::ByteStr(v) => v.span(),
183            Self::CStr(v) => v.span(),
184            Self::Char(v) => v.span(),
185            Self::Byte(v) => v.span(),
186            Self::Bool(v) => v.span(),
187            Self::Verbatim(v) => v.span(),
188        }
189    }
190
191    #[inline]
192    pub fn set_span(&mut self, span: Span) {
193        match self {
194            Self::Int(v) => v.set_span(span),
195            Self::Float(v) => v.set_span(span),
196            Self::Str(v) => v.set_span(span),
197            Self::ByteStr(v) => v.set_span(span),
198            Self::CStr(v) => v.set_span(span),
199            Self::Char(v) => v.set_span(span),
200            Self::Byte(v) => v.set_span(span),
201            Self::Bool(v) => v.set_span(span),
202            Self::Verbatim(v) => v.set_span(span),
203        }
204    }
205}
206
207impl Spanner for Lit {
208    fn span(&self) -> Span {
209        self.span()
210    }
211}
212
213impl std::fmt::Display for Lit {
214    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
215        f.write_str(self.repr())
216    }
217}
218
219#[cfg(feature = "serde")]
220impl From<Lit> for String {
221    fn from(value: Lit) -> Self {
222        value.repr().to_string()
223    }
224}
225
226impl Scan for Lit {
227    fn scan(cursor: Cursor<'_>) -> Result<(Cursor<'_>, Self), LexError> {
228        if let Ok((end, v)) = LitBool::scan(cursor) {
229            return Ok((end, Self::Bool(v)));
230        }
231
232        if let Ok((end, v)) = LitByte::scan(cursor) {
233            return Ok((end, Self::Byte(v)));
234        }
235
236        if let Ok((end, v)) = LitByteStr::scan(cursor) {
237            return Ok((end, Self::ByteStr(v)));
238        }
239
240        if let Ok((end, v)) = LitCStr::scan(cursor) {
241            return Ok((end, Self::CStr(v)));
242        }
243
244        if let Ok((end, v)) = LitStr::scan(cursor) {
245            return Ok((end, Self::Str(v)));
246        }
247
248        if let Ok((end, v)) = LitChar::scan(cursor) {
249            return Ok((end, Self::Char(v)));
250        }
251
252        if let Ok((end, v)) = LitFloat::scan(cursor) {
253            return Ok((end, Self::Float(v)));
254        }
255
256        if let Ok((end, v)) = LitInt::scan(cursor) {
257            return Ok((end, Self::Int(v)));
258        }
259
260        cursor.error().into()
261    }
262}
263
264impl ToTokens for Lit {
265    fn to_tokens(&self, tokens: &mut TokenStream) {
266        tokens.extend_one(TokenTree::Literal(self.clone()));
267    }
268}