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 | |
116 | 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 | |