use proc_macro::{Delimiter, Group, Punct, Spacing, Span, TokenTree};
pub fn parse_group(
iter: &mut impl Iterator<Item = TokenTree>,
parent_span: Span,
hints: &str,
) -> Result<Group, (Span, String)>
{
if let Some(tree) = iter.next()
{
check_group(tree, hints)
}
else
{
return Err((
parent_span,
"Unexpected end of macro invocation. Expected '[', '{', or '('.\n".to_string() + hints,
));
}
}
pub fn check_group(tree: TokenTree, hints: &str) -> Result<Group, (Span, String)>
{
if let TokenTree::Group(group) = tree
{
check_delimiter(&group)?;
Ok(group)
}
else
{
return Err((
tree.span(),
"Unexpected token. Expected '[', '{', or '('.\n".to_string() + hints,
));
}
}
pub fn check_delimiter(group: &Group) -> Result<(), (Span, String)>
{
if group.delimiter() == Delimiter::None
{
return Err((
group.span(),
"Unexpected delimiter for group. Expected '[]','{}', or '()' but received none.".into(),
));
}
Ok(())
}
pub fn punct_is_char(p: &Punct, c: char) -> bool
{
p.as_char() == c && p.spacing() == Spacing::Alone
}
pub fn is_semicolon(p: &Punct) -> bool
{
punct_is_char(p, ';')
}
pub fn is_nested_invocation(p: &Punct) -> bool
{
punct_is_char(p, '#')
}
pub fn next_token(
iter: &mut impl Iterator<Item = TokenTree>,
err_msg: &str,
) -> Result<Option<TokenTree>, (Span, String)>
{
match iter.next()
{
Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::None =>
{
let mut in_group = group.stream().into_iter();
let result = in_group.next();
match in_group.next()
{
None => Ok(result),
Some(TokenTree::Punct(p)) if is_semicolon(&p) && in_group.next().is_none() =>
{
Ok(result)
},
_ => Err((group.span(), err_msg.into())),
}
},
token => Ok(token),
}
}