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