1 use std::convert::TryFrom;
2 
3 use crate::{Literal, err::{InvalidToken, TokenKind}};
4 
5 
6 /// Helper macro to call a `callback` macro four times for all combinations of
7 /// `proc_macro`/`proc_macro2` and `&`/owned.
8 macro_rules! helper {
9     ($callback:ident, $($input:tt)*) => {
10         $callback!([proc_macro::] => $($input)*);
11         $callback!([&proc_macro::] => $($input)*);
12         #[cfg(feature = "proc-macro2")]
13         $callback!([proc_macro2::] => $($input)*);
14         #[cfg(feature = "proc-macro2")]
15         $callback!([&proc_macro2::] => $($input)*);
16     };
17 }
18 
19 /// Like `helper!` but without reference types.
20 macro_rules! helper_no_refs {
21     ($callback:ident, $($input:tt)*) => {
22         $callback!([proc_macro::] => $($input)*);
23         #[cfg(feature = "proc-macro2")]
24         $callback!([proc_macro2::] => $($input)*);
25     };
26 }
27 
28 
29 // ==============================================================================================
30 // ===== `From<*Lit> for Literal`
31 // ==============================================================================================
32 
33 macro_rules! impl_specific_lit_to_lit {
34     ($ty:ty, $variant:ident) => {
35         impl<B: crate::Buffer> From<$ty> for Literal<B> {
36             fn from(src: $ty) -> Self {
37                 Literal::$variant(src)
38             }
39         }
40     };
41 }
42 
43 impl_specific_lit_to_lit!(crate::BoolLit, Bool);
44 impl_specific_lit_to_lit!(crate::IntegerLit<B>, Integer);
45 impl_specific_lit_to_lit!(crate::FloatLit<B>, Float);
46 impl_specific_lit_to_lit!(crate::CharLit<B>, Char);
47 impl_specific_lit_to_lit!(crate::StringLit<B>, String);
48 impl_specific_lit_to_lit!(crate::ByteLit<B>, Byte);
49 impl_specific_lit_to_lit!(crate::ByteStringLit<B>, ByteString);
50 
51 
52 
53 // ==============================================================================================
54 // ===== `From<pm::Literal> for Literal`
55 // ==============================================================================================
56 
57 
58 macro_rules! impl_tt_to_lit {
59     ([$($prefix:tt)*] => ) => {
60         impl From<$($prefix)* Literal> for Literal<String> {
61             fn from(src: $($prefix)* Literal) -> Self {
62                 // We call `expect` in all these impls: this library aims to implement exactly
63                 // the Rust grammar, so if we have a valid Rust literal, we should always be
64                 // able to parse it.
65                 Self::parse(src.to_string())
66                     .expect("bug: failed to parse output of `Literal::to_string`")
67             }
68         }
69     }
70 }
71 
72 helper!(impl_tt_to_lit, );
73 
74 
75 // ==============================================================================================
76 // ===== `TryFrom<pm::TokenTree> for Literal`
77 // ==============================================================================================
78 
79 macro_rules! impl_tt_to_lit {
80     ([$($prefix:tt)*] => ) => {
81         impl TryFrom<$($prefix)* TokenTree> for Literal<String> {
82             type Error = InvalidToken;
83             fn try_from(tt: $($prefix)* TokenTree) -> Result<Self, Self::Error> {
84                 let span = tt.span();
85                 let res = match tt {
86                     $($prefix)* TokenTree::Group(_) => Err(TokenKind::Group),
87                     $($prefix)* TokenTree::Punct(_) => Err(TokenKind::Punct),
88                     $($prefix)* TokenTree::Ident(ref ident) if ident.to_string() == "true"
89                         => return Ok(Literal::Bool(crate::BoolLit::True)),
90                     $($prefix)* TokenTree::Ident(ref ident) if ident.to_string() == "false"
91                         => return Ok(Literal::Bool(crate::BoolLit::False)),
92                     $($prefix)* TokenTree::Ident(_) => Err(TokenKind::Ident),
93                     $($prefix)* TokenTree::Literal(ref lit) => Ok(lit),
94                 };
95 
96                 match res {
97                     Ok(lit) => Ok(From::from(lit)),
98                     Err(actual) => Err(InvalidToken {
99                         actual,
100                         expected: TokenKind::Literal,
101                         span: span.into(),
102                     }),
103                 }
104             }
105         }
106     }
107 }
108 
109 helper!(impl_tt_to_lit, );
110 
111 
112 // ==============================================================================================
113 // ===== `TryFrom<pm::Literal>`, `TryFrom<pm::TokenTree>` for non-bool `*Lit`
114 // ==============================================================================================
115 
kind_of(lit: &Literal<String>) -> TokenKind116 fn kind_of(lit: &Literal<String>) -> TokenKind {
117     match lit {
118         Literal::String(_) => TokenKind::StringLit,
119         Literal::Bool(_) => TokenKind::BoolLit,
120         Literal::Integer(_) => TokenKind::IntegerLit,
121         Literal::Float(_) => TokenKind::FloatLit,
122         Literal::Char(_) => TokenKind::CharLit,
123         Literal::Byte(_) => TokenKind::ByteLit,
124         Literal::ByteString(_) => TokenKind::ByteStringLit,
125     }
126 }
127 
128 macro_rules! impl_for_specific_lit {
129     ([$($prefix:tt)*] => $ty:ty, $variant:ident, $kind:ident) => {
130         impl TryFrom<$($prefix)* Literal> for $ty {
131             type Error = InvalidToken;
132             fn try_from(src: $($prefix)* Literal) -> Result<Self, Self::Error> {
133                 let span = src.span();
134                 let lit: Literal<String> = src.into();
135                 match lit {
136                     Literal::$variant(s) => Ok(s),
137                     other => Err(InvalidToken {
138                         expected: TokenKind::$kind,
139                         actual: kind_of(&other),
140                         span: span.into(),
141                     }),
142                 }
143             }
144         }
145 
146         impl TryFrom<$($prefix)* TokenTree> for $ty {
147             type Error = InvalidToken;
148             fn try_from(tt: $($prefix)* TokenTree) -> Result<Self, Self::Error> {
149                 let span = tt.span();
150                 let res = match tt {
151                     $($prefix)* TokenTree::Group(_) => Err(TokenKind::Group),
152                     $($prefix)* TokenTree::Punct(_) => Err(TokenKind::Punct),
153                     $($prefix)* TokenTree::Ident(_) => Err(TokenKind::Ident),
154                     $($prefix)* TokenTree::Literal(ref lit) => Ok(lit),
155                 };
156 
157                 match res {
158                     Ok(lit) => <$ty>::try_from(lit),
159                     Err(actual) => Err(InvalidToken {
160                         actual,
161                         expected: TokenKind::$kind,
162                         span: span.into(),
163                     }),
164                 }
165             }
166         }
167     };
168 }
169 
170 helper!(impl_for_specific_lit, crate::IntegerLit<String>, Integer, IntegerLit);
171 helper!(impl_for_specific_lit, crate::FloatLit<String>, Float, FloatLit);
172 helper!(impl_for_specific_lit, crate::CharLit<String>, Char, CharLit);
173 helper!(impl_for_specific_lit, crate::StringLit<String>, String, StringLit);
174 helper!(impl_for_specific_lit, crate::ByteLit<String>, Byte, ByteLit);
175 helper!(impl_for_specific_lit, crate::ByteStringLit<String>, ByteString, ByteStringLit);
176 
177 
178 // ==============================================================================================
179 // ===== `From<*Lit> for pm::Literal`
180 // ==============================================================================================
181 
182 macro_rules! impl_specific_lit_to_pm_lit {
183     ([$($prefix:tt)*] => $ty:ident, $variant:ident, $kind:ident) => {
184         impl<B: crate::Buffer> From<crate::$ty<B>> for $($prefix)* Literal {
185             fn from(l: crate::$ty<B>) -> Self {
186                 // This should never fail: an input that is parsed successfuly
187                 // as one of our literal types should always parse as a
188                 // proc_macro literal as well!
189                 l.raw_input().parse().unwrap_or_else(|e| {
190                     panic!(
191                         "failed to parse `{}` as `{}`: {}",
192                         l.raw_input(),
193                         std::any::type_name::<Self>(),
194                         e,
195                     )
196                 })
197             }
198         }
199     };
200 }
201 
202 helper_no_refs!(impl_specific_lit_to_pm_lit, IntegerLit, Integer, IntegerLit);
203 helper_no_refs!(impl_specific_lit_to_pm_lit, FloatLit, Float, FloatLit);
204 helper_no_refs!(impl_specific_lit_to_pm_lit, CharLit, Char, CharLit);
205 helper_no_refs!(impl_specific_lit_to_pm_lit, StringLit, String, StringLit);
206 helper_no_refs!(impl_specific_lit_to_pm_lit, ByteLit, Byte, ByteLit);
207 helper_no_refs!(impl_specific_lit_to_pm_lit, ByteStringLit, ByteString, ByteStringLit);
208 
209 
210 // ==============================================================================================
211 // ===== `TryFrom<pm::TokenTree> for BoolLit`
212 // ==============================================================================================
213 
214 macro_rules! impl_from_tt_for_bool {
215     ([$($prefix:tt)*] => ) => {
216         impl TryFrom<$($prefix)* TokenTree> for crate::BoolLit {
217             type Error = InvalidToken;
218             fn try_from(tt: $($prefix)* TokenTree) -> Result<Self, Self::Error> {
219                 let span = tt.span();
220                 let actual = match tt {
221                     $($prefix)* TokenTree::Ident(ref ident) if ident.to_string() == "true"
222                         => return Ok(crate::BoolLit::True),
223                     $($prefix)* TokenTree::Ident(ref ident) if ident.to_string() == "false"
224                         => return Ok(crate::BoolLit::False),
225 
226                     $($prefix)* TokenTree::Group(_) => TokenKind::Group,
227                     $($prefix)* TokenTree::Punct(_) => TokenKind::Punct,
228                     $($prefix)* TokenTree::Ident(_) => TokenKind::Ident,
229                     $($prefix)* TokenTree::Literal(ref lit) => kind_of(&Literal::from(lit)),
230                 };
231 
232                 Err(InvalidToken {
233                     actual,
234                     expected: TokenKind::BoolLit,
235                     span: span.into(),
236                 })
237             }
238         }
239     };
240 }
241 
242 helper!(impl_from_tt_for_bool, );
243 
244 // ==============================================================================================
245 // ===== `From<BoolLit> for pm::Ident`
246 // ==============================================================================================
247 
248 macro_rules! impl_bool_lit_to_pm_lit {
249     ([$($prefix:tt)*] => ) => {
250         impl From<crate::BoolLit> for $($prefix)* Ident {
251             fn from(l: crate::BoolLit) -> Self {
252                 Self::new(l.as_str(), $($prefix)* Span::call_site())
253             }
254         }
255     };
256 }
257 
258 helper_no_refs!(impl_bool_lit_to_pm_lit, );
259 
260 
261 mod tests {
262     //! # Tests
263     //!
264     //! ```no_run
265     //! extern crate proc_macro;
266     //!
267     //! use std::convert::TryFrom;
268     //! use litrs::Literal;
269     //!
270     //! fn give<T>() -> T {
271     //!     panic!()
272     //! }
273     //!
274     //! let _ = litrs::Literal::<String>::from(give::<litrs::BoolLit>());
275     //! let _ = litrs::Literal::<String>::from(give::<litrs::IntegerLit<String>>());
276     //! let _ = litrs::Literal::<String>::from(give::<litrs::FloatLit<String>>());
277     //! let _ = litrs::Literal::<String>::from(give::<litrs::CharLit<String>>());
278     //! let _ = litrs::Literal::<String>::from(give::<litrs::StringLit<String>>());
279     //! let _ = litrs::Literal::<String>::from(give::<litrs::ByteLit<String>>());
280     //! let _ = litrs::Literal::<String>::from(give::<litrs::ByteStringLit<String>>());
281     //!
282     //! let _ = litrs::Literal::<&'static str>::from(give::<litrs::BoolLit>());
283     //! let _ = litrs::Literal::<&'static str>::from(give::<litrs::IntegerLit<&'static str>>());
284     //! let _ = litrs::Literal::<&'static str>::from(give::<litrs::FloatLit<&'static str>>());
285     //! let _ = litrs::Literal::<&'static str>::from(give::<litrs::CharLit<&'static str>>());
286     //! let _ = litrs::Literal::<&'static str>::from(give::<litrs::StringLit<&'static str>>());
287     //! let _ = litrs::Literal::<&'static str>::from(give::<litrs::ByteLit<&'static str>>());
288     //! let _ = litrs::Literal::<&'static str>::from(give::<litrs::ByteStringLit<&'static str>>());
289     //!
290     //!
291     //! let _ = litrs::Literal::from(give::<proc_macro::Literal>());
292     //! let _ = litrs::Literal::from(give::<&proc_macro::Literal>());
293     //!
294     //! let _ = litrs::Literal::try_from(give::<proc_macro::TokenTree>());
295     //! let _ = litrs::Literal::try_from(give::<&proc_macro::TokenTree>());
296     //!
297     //!
298     //! let _ = litrs::IntegerLit::try_from(give::<proc_macro::Literal>());
299     //! let _ = litrs::IntegerLit::try_from(give::<&proc_macro::Literal>());
300     //!
301     //! let _ = litrs::FloatLit::try_from(give::<proc_macro::Literal>());
302     //! let _ = litrs::FloatLit::try_from(give::<&proc_macro::Literal>());
303     //!
304     //! let _ = litrs::CharLit::try_from(give::<proc_macro::Literal>());
305     //! let _ = litrs::CharLit::try_from(give::<&proc_macro::Literal>());
306     //!
307     //! let _ = litrs::StringLit::try_from(give::<proc_macro::Literal>());
308     //! let _ = litrs::StringLit::try_from(give::<&proc_macro::Literal>());
309     //!
310     //! let _ = litrs::ByteLit::try_from(give::<proc_macro::Literal>());
311     //! let _ = litrs::ByteLit::try_from(give::<&proc_macro::Literal>());
312     //!
313     //! let _ = litrs::ByteStringLit::try_from(give::<proc_macro::Literal>());
314     //! let _ = litrs::ByteStringLit::try_from(give::<&proc_macro::Literal>());
315     //!
316     //!
317     //! let _ = litrs::BoolLit::try_from(give::<proc_macro::TokenTree>());
318     //! let _ = litrs::BoolLit::try_from(give::<&proc_macro::TokenTree>());
319     //!
320     //! let _ = litrs::IntegerLit::try_from(give::<proc_macro::TokenTree>());
321     //! let _ = litrs::IntegerLit::try_from(give::<&proc_macro::TokenTree>());
322     //!
323     //! let _ = litrs::FloatLit::try_from(give::<proc_macro::TokenTree>());
324     //! let _ = litrs::FloatLit::try_from(give::<&proc_macro::TokenTree>());
325     //!
326     //! let _ = litrs::CharLit::try_from(give::<proc_macro::TokenTree>());
327     //! let _ = litrs::CharLit::try_from(give::<&proc_macro::TokenTree>());
328     //!
329     //! let _ = litrs::StringLit::try_from(give::<proc_macro::TokenTree>());
330     //! let _ = litrs::StringLit::try_from(give::<&proc_macro::TokenTree>());
331     //!
332     //! let _ = litrs::ByteLit::try_from(give::<proc_macro::TokenTree>());
333     //! let _ = litrs::ByteLit::try_from(give::<&proc_macro::TokenTree>());
334     //!
335     //! let _ = litrs::ByteStringLit::try_from(give::<proc_macro::TokenTree>());
336     //! let _ = litrs::ByteStringLit::try_from(give::<&proc_macro::TokenTree>());
337     //! ```
338 }
339 
340 #[cfg(feature = "proc-macro2")]
341 mod tests_proc_macro2 {
342     //! # Tests
343     //!
344     //! ```no_run
345     //! extern crate proc_macro;
346     //!
347     //! use std::convert::TryFrom;
348     //! use litrs::Literal;
349     //!
350     //! fn give<T>() -> T {
351     //!     panic!()
352     //! }
353     //!
354     //! let _ = litrs::Literal::from(give::<proc_macro2::Literal>());
355     //! let _ = litrs::Literal::from(give::<&proc_macro2::Literal>());
356     //!
357     //! let _ = litrs::Literal::try_from(give::<proc_macro2::TokenTree>());
358     //! let _ = litrs::Literal::try_from(give::<&proc_macro2::TokenTree>());
359     //!
360     //!
361     //! let _ = litrs::IntegerLit::try_from(give::<proc_macro2::Literal>());
362     //! let _ = litrs::IntegerLit::try_from(give::<&proc_macro2::Literal>());
363     //!
364     //! let _ = litrs::FloatLit::try_from(give::<proc_macro2::Literal>());
365     //! let _ = litrs::FloatLit::try_from(give::<&proc_macro2::Literal>());
366     //!
367     //! let _ = litrs::CharLit::try_from(give::<proc_macro2::Literal>());
368     //! let _ = litrs::CharLit::try_from(give::<&proc_macro2::Literal>());
369     //!
370     //! let _ = litrs::StringLit::try_from(give::<proc_macro2::Literal>());
371     //! let _ = litrs::StringLit::try_from(give::<&proc_macro2::Literal>());
372     //!
373     //! let _ = litrs::ByteLit::try_from(give::<proc_macro2::Literal>());
374     //! let _ = litrs::ByteLit::try_from(give::<&proc_macro2::Literal>());
375     //!
376     //! let _ = litrs::ByteStringLit::try_from(give::<proc_macro2::Literal>());
377     //! let _ = litrs::ByteStringLit::try_from(give::<&proc_macro2::Literal>());
378     //!
379     //!
380     //! let _ = litrs::BoolLit::try_from(give::<proc_macro2::TokenTree>());
381     //! let _ = litrs::BoolLit::try_from(give::<&proc_macro2::TokenTree>());
382     //!
383     //! let _ = litrs::IntegerLit::try_from(give::<proc_macro2::TokenTree>());
384     //! let _ = litrs::IntegerLit::try_from(give::<&proc_macro2::TokenTree>());
385     //!
386     //! let _ = litrs::FloatLit::try_from(give::<proc_macro2::TokenTree>());
387     //! let _ = litrs::FloatLit::try_from(give::<&proc_macro2::TokenTree>());
388     //!
389     //! let _ = litrs::CharLit::try_from(give::<proc_macro2::TokenTree>());
390     //! let _ = litrs::CharLit::try_from(give::<&proc_macro2::TokenTree>());
391     //!
392     //! let _ = litrs::StringLit::try_from(give::<proc_macro2::TokenTree>());
393     //! let _ = litrs::StringLit::try_from(give::<&proc_macro2::TokenTree>());
394     //!
395     //! let _ = litrs::ByteLit::try_from(give::<proc_macro2::TokenTree>());
396     //! let _ = litrs::ByteLit::try_from(give::<&proc_macro2::TokenTree>());
397     //!
398     //! let _ = litrs::ByteStringLit::try_from(give::<proc_macro2::TokenTree>());
399     //! let _ = litrs::ByteStringLit::try_from(give::<&proc_macro2::TokenTree>());
400     //! ```
401 }
402