use proc_macro2::{Delimiter, Ident, TokenStream, extra::DelimSpan};
use syn::{
Token, bracketed,
parse::{Parse, ParseStream, discouraged::AnyDelimiter},
token::Bracket,
};
pub(crate) struct ItemMacroRules {
#[allow(dead_code)]
attrs: Vec<Attribute>,
#[allow(dead_code)]
macro_rules: inner::macro_rules,
#[allow(dead_code)]
bang: Token![!],
#[allow(dead_code)]
name: Ident,
#[allow(dead_code)]
delim: MacroDelimiter,
pub(crate) tokens: TokenStream,
}
impl Parse for ItemMacroRules {
fn parse(input: ParseStream) -> syn::Result<ItemMacroRules> {
let tokens;
Ok(ItemMacroRules {
attrs: Attribute::parse_outer(input)?,
macro_rules: input.parse()?,
bang: input.parse()?,
name: input.parse()?,
delim: {
let (delimiter, content) = parse_delimited(input)?;
tokens = content;
delimiter
},
tokens,
})
}
}
#[allow(dead_code)]
struct Attribute {
pound: Token![#],
bracket: Bracket,
inner: TokenStream,
}
impl Parse for Attribute {
fn parse(input: ParseStream) -> syn::Result<Attribute> {
let tokens;
Ok(Attribute {
pound: input.parse()?,
bracket: bracketed!(tokens in input),
inner: tokens.parse()?,
})
}
}
impl Attribute {
fn parse_outer(input: ParseStream) -> syn::Result<Vec<Attribute>> {
let mut attrs = Vec::new();
while input.peek(Token![#]) {
attrs.push(input.parse()?);
}
Ok(attrs)
}
}
fn parse_delimited(input: ParseStream) -> syn::Result<(MacroDelimiter, TokenStream)> {
let (delim, span, inner) = input.parse_any_delimiter()?;
let delim = match delim {
Delimiter::Parenthesis => MacroDelimiter { _inner: span },
Delimiter::Brace => MacroDelimiter { _inner: span },
Delimiter::Bracket => MacroDelimiter { _inner: span },
Delimiter::None => {
return Err(syn::Error::new(
span.join(),
"`expandable` does not support « None delimiters »",
));
}
};
let inner = inner.parse()?;
Ok((delim, inner))
}
struct MacroDelimiter {
_inner: DelimSpan,
}
mod inner {
syn::custom_keyword!(macro_rules);
}