use std::convert::TryFrom;
use crate::{
err::{InvalidToken, TokenKind},
Literal,
};
macro_rules! helper {
($callback:ident, $($input:tt)*) => {
$callback!([proc_macro::] => $($input)*);
$callback!([&proc_macro::] => $($input)*);
#[cfg(feature = "proc-macro2")]
$callback!([proc_macro2::] => $($input)*);
#[cfg(feature = "proc-macro2")]
$callback!([&proc_macro2::] => $($input)*);
};
}
macro_rules! helper_no_refs {
($callback:ident, $($input:tt)*) => {
$callback!([proc_macro::] => $($input)*);
#[cfg(feature = "proc-macro2")]
$callback!([proc_macro2::] => $($input)*);
};
}
macro_rules! impl_specific_lit_to_lit {
($ty:ty, $variant:ident) => {
impl<B: crate::Buffer> From<$ty> for Literal<B> {
fn from(src: $ty) -> Self {
Literal::$variant(src)
}
}
};
}
impl_specific_lit_to_lit!(crate::BoolLit, Bool);
impl_specific_lit_to_lit!(crate::IntegerLit<B>, Integer);
impl_specific_lit_to_lit!(crate::FloatLit<B>, Float);
impl_specific_lit_to_lit!(crate::CharLit<B>, Char);
impl_specific_lit_to_lit!(crate::StringLit<B>, String);
impl_specific_lit_to_lit!(crate::ByteLit<B>, Byte);
impl_specific_lit_to_lit!(crate::ByteStringLit<B>, ByteString);
impl_specific_lit_to_lit!(crate::CStringLit<B>, CString);
macro_rules! impl_tt_to_lit {
([$($prefix:tt)*] => ) => {
impl From<$($prefix)* Literal> for Literal<String> {
fn from(src: $($prefix)* Literal) -> Self {
Self::parse(src.to_string())
.expect("bug: failed to parse output of `Literal::to_string`")
}
}
}
}
helper!(impl_tt_to_lit,);
macro_rules! impl_tt_to_lit {
([$($prefix:tt)*] => ) => {
impl TryFrom<$($prefix)* TokenTree> for Literal<String> {
type Error = InvalidToken;
fn try_from(tt: $($prefix)* TokenTree) -> Result<Self, Self::Error> {
let span = tt.span();
let res = match tt {
$($prefix)* TokenTree::Group(_) => Err(TokenKind::Group),
$($prefix)* TokenTree::Punct(_) => Err(TokenKind::Punct),
$($prefix)* TokenTree::Ident(ref ident) if ident.to_string() == "true"
=> return Ok(Literal::Bool(crate::BoolLit::True)),
$($prefix)* TokenTree::Ident(ref ident) if ident.to_string() == "false"
=> return Ok(Literal::Bool(crate::BoolLit::False)),
$($prefix)* TokenTree::Ident(_) => Err(TokenKind::Ident),
$($prefix)* TokenTree::Literal(ref lit) => Ok(lit),
};
match res {
Ok(lit) => Ok(From::from(lit)),
Err(actual) => Err(InvalidToken {
actual,
expected: TokenKind::Literal,
span: span.into(),
}),
}
}
}
}
}
helper!(impl_tt_to_lit,);
fn kind_of(lit: &Literal<String>) -> TokenKind {
match lit {
Literal::String(_) => TokenKind::StringLit,
Literal::Bool(_) => TokenKind::BoolLit,
Literal::Integer(_) => TokenKind::IntegerLit,
Literal::Float(_) => TokenKind::FloatLit,
Literal::Char(_) => TokenKind::CharLit,
Literal::Byte(_) => TokenKind::ByteLit,
Literal::ByteString(_) => TokenKind::ByteStringLit,
Literal::CString(_) => TokenKind::CStringLit,
}
}
macro_rules! impl_for_specific_lit {
([$($prefix:tt)*] => $ty:ty, $variant:ident, $kind:ident) => {
impl TryFrom<$($prefix)* Literal> for $ty {
type Error = InvalidToken;
fn try_from(src: $($prefix)* Literal) -> Result<Self, Self::Error> {
let span = src.span();
let lit: Literal<String> = src.into();
match lit {
Literal::$variant(s) => Ok(s),
other => Err(InvalidToken {
expected: TokenKind::$kind,
actual: kind_of(&other),
span: span.into(),
}),
}
}
}
impl TryFrom<$($prefix)* TokenTree> for $ty {
type Error = InvalidToken;
fn try_from(tt: $($prefix)* TokenTree) -> Result<Self, Self::Error> {
let span = tt.span();
let res = match tt {
$($prefix)* TokenTree::Group(_) => Err(TokenKind::Group),
$($prefix)* TokenTree::Punct(_) => Err(TokenKind::Punct),
$($prefix)* TokenTree::Ident(_) => Err(TokenKind::Ident),
$($prefix)* TokenTree::Literal(ref lit) => Ok(lit),
};
match res {
Ok(lit) => <$ty>::try_from(lit),
Err(actual) => Err(InvalidToken {
actual,
expected: TokenKind::$kind,
span: span.into(),
}),
}
}
}
};
}
helper!(impl_for_specific_lit, crate::IntegerLit<String>, Integer, IntegerLit);
helper!(impl_for_specific_lit, crate::FloatLit<String>, Float, FloatLit);
helper!(impl_for_specific_lit, crate::CharLit<String>, Char, CharLit);
helper!(impl_for_specific_lit, crate::StringLit<String>, String, StringLit);
helper!(impl_for_specific_lit, crate::ByteLit<String>, Byte, ByteLit);
helper!(impl_for_specific_lit, crate::ByteStringLit<String>, ByteString, ByteStringLit);
helper!(impl_for_specific_lit, crate::CStringLit<String>, CString, CStringLit);
macro_rules! impl_specific_lit_to_pm_lit {
([$($prefix:tt)*] => $ty:ident, $variant:ident, $kind:ident) => {
impl<B: crate::Buffer> From<crate::$ty<B>> for $($prefix)* Literal {
fn from(l: crate::$ty<B>) -> Self {
l.raw_input().parse().unwrap_or_else(|e| {
panic!(
"failed to parse `{}` as `{}`: {}",
l.raw_input(),
std::any::type_name::<Self>(),
e,
)
})
}
}
};
}
helper_no_refs!(impl_specific_lit_to_pm_lit, IntegerLit, Integer, IntegerLit);
helper_no_refs!(impl_specific_lit_to_pm_lit, FloatLit, Float, FloatLit);
helper_no_refs!(impl_specific_lit_to_pm_lit, CharLit, Char, CharLit);
helper_no_refs!(impl_specific_lit_to_pm_lit, StringLit, String, StringLit);
helper_no_refs!(impl_specific_lit_to_pm_lit, ByteLit, Byte, ByteLit);
helper_no_refs!(impl_specific_lit_to_pm_lit, ByteStringLit, ByteString, ByteStringLit);
helper_no_refs!(impl_specific_lit_to_pm_lit, CStringLit, CString, CStringLit);
macro_rules! impl_from_tt_for_bool {
([$($prefix:tt)*] => ) => {
impl TryFrom<$($prefix)* TokenTree> for crate::BoolLit {
type Error = InvalidToken;
fn try_from(tt: $($prefix)* TokenTree) -> Result<Self, Self::Error> {
let span = tt.span();
let actual = match tt {
$($prefix)* TokenTree::Ident(ref ident) if ident.to_string() == "true"
=> return Ok(crate::BoolLit::True),
$($prefix)* TokenTree::Ident(ref ident) if ident.to_string() == "false"
=> return Ok(crate::BoolLit::False),
$($prefix)* TokenTree::Group(_) => TokenKind::Group,
$($prefix)* TokenTree::Punct(_) => TokenKind::Punct,
$($prefix)* TokenTree::Ident(_) => TokenKind::Ident,
$($prefix)* TokenTree::Literal(ref lit) => kind_of(&Literal::from(lit)),
};
Err(InvalidToken {
actual,
expected: TokenKind::BoolLit,
span: span.into(),
})
}
}
};
}
helper!(impl_from_tt_for_bool,);
macro_rules! impl_bool_lit_to_pm_lit {
([$($prefix:tt)*] => ) => {
impl From<crate::BoolLit> for $($prefix)* Ident {
fn from(l: crate::BoolLit) -> Self {
Self::new(l.as_str(), $($prefix)* Span::call_site())
}
}
};
}
helper_no_refs!(impl_bool_lit_to_pm_lit,);
mod tests {
}
#[cfg(feature = "proc-macro2")]
mod tests_proc_macro2 {
}