Skip to main content

moxy_token/lit/
mod.rs

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