use proc_macro2::{Delimiter, Span, TokenStream, TokenTree};
#[derive(Default)]
pub struct GlobalAttr {
pub ignore: Vec<syn::Type>,
pub debug: bool,
pub prefix: Option<syn::Type>,
pub suffix: Option<syn::Type>,
pub parse_type: Option<syn::Type>,
}
fn parse_type(
span: Span,
mut tokens: proc_macro2::token_stream::IntoIter,
) -> syn::Result<syn::Type> {
match tokens.next() {
Some(TokenTree::Punct(p)) => {
if p.as_char() != '=' {
return Err(syn::Error::new_spanned(p, "expected an '=' to follow"));
}
}
Some(t) => return Err(syn::Error::new_spanned(t, "expected an '=' to follow")),
None => return Err(syn::Error::new(span, "expected an '=' to follow")),
}
let mut stream = TokenStream::new();
stream.extend(tokens);
syn::parse2(stream)
}
impl GlobalAttr {
pub fn parse_attrs(attrs: Vec<syn::Attribute>) -> syn::Result<Self> {
let mut output = GlobalAttr::default();
for attr in attrs {
if attr.path.is_ident("nommy") {
output.parse_attr(attr.tokens)?;
}
}
Ok(output)
}
pub fn parse_attr(&mut self, tokens: TokenStream) -> syn::Result<()> {
for tt in tokens.into_iter() {
let (inner, span) = match tt {
TokenTree::Group(g) => {
if g.delimiter() == Delimiter::Parenthesis {
(g.stream(), g.span())
} else {
return Err(syn::Error::new_spanned(
g,
"expected parenthesied attribute arguments",
));
}
}
t => {
return Err(syn::Error::new_spanned(
t,
"expected parenthesied attribute arguments",
))
}
};
self.parse_args(span, inner)?;
}
Ok(())
}
pub fn parse_args(&mut self, mut span: Span, tokens: TokenStream) -> syn::Result<()> {
let mut stream = TokenStream::new();
for tt in tokens {
match tt {
TokenTree::Punct(p) => {
if p.as_char() == ',' {
let mut tmp = TokenStream::new();
std::mem::swap(&mut stream, &mut tmp);
self.parse_arg(span, tmp)?;
span = p.span();
} else {
stream.extend(vec![TokenTree::Punct(p)])
}
}
_ => stream.extend(vec![tt]),
}
}
self.parse_arg(span, stream)
}
pub fn parse_arg(&mut self, span: Span, tokens: TokenStream) -> syn::Result<()> {
let mut tokens = tokens.into_iter();
let ident = match tokens.next() {
Some(TokenTree::Ident(i)) => i,
Some(t) => return Err(syn::Error::new_spanned(t, "expected ident")),
None => return Err(syn::Error::new(span, "expected ident to follow")),
};
match ident.to_string().as_ref() {
"ignore" => self.ignore.push(parse_type(ident.span(), tokens)?),
"prefix" => self.prefix = Some(parse_type(ident.span(), tokens)?),
"suffix" => self.suffix = Some(parse_type(ident.span(), tokens)?),
"parse_type" => self.parse_type = Some(parse_type(ident.span(), tokens)?),
"debug" => self.debug = true,
_ => return Err(syn::Error::new_spanned(ident, "unknown parameter")),
}
Ok(())
}
}
#[derive(Default)]
pub struct FieldAttr {
pub prefix: Option<syn::Type>,
pub suffix: Option<syn::Type>,
pub parser: Option<syn::Type>,
pub vec: VecFieldAttr,
}
#[derive(Default)]
pub struct VecFieldAttr {
pub count: Option<syn::Expr>,
pub min: Option<syn::Expr>,
pub max: Option<syn::Expr>,
pub parser: Option<syn::Type>,
}
impl VecFieldAttr {
pub fn is_some(&self) -> bool {
self.count.is_some() || self.min.is_some() || self.max.is_some() || self.parser.is_some()
}
}
impl FieldAttr {
pub fn parse_attrs(attrs: Vec<syn::Attribute>) -> syn::Result<Self> {
let mut output = FieldAttr::default();
for attr in attrs {
if attr.path.is_ident("nommy") {
output.parse_attr(attr.tokens)?;
}
}
Ok(output)
}
pub fn parse_attr(&mut self, tokens: TokenStream) -> syn::Result<()> {
for tt in tokens.into_iter() {
let (inner, span) = match tt {
TokenTree::Group(g) => {
if g.delimiter() == Delimiter::Parenthesis {
(g.stream(), g.span())
} else {
return Err(syn::Error::new_spanned(
g,
"expected parenthesied attribute arguments",
));
}
}
t => {
return Err(syn::Error::new_spanned(
t,
"expected parenthesied attribute arguments",
))
}
};
self.parse_args(span, inner)?;
}
Ok(())
}
pub fn parse_args(&mut self, mut span: Span, tokens: TokenStream) -> syn::Result<()> {
let mut stream = TokenStream::new();
for tt in tokens {
match tt {
TokenTree::Punct(p) => {
if p.as_char() == ',' {
let mut tmp = TokenStream::new();
std::mem::swap(&mut stream, &mut tmp);
self.parse_arg(span, tmp)?;
span = p.span();
} else {
stream.extend(vec![TokenTree::Punct(p)])
}
}
_ => stream.extend(vec![tt]),
}
}
self.parse_arg(span, stream)
}
pub fn parse_arg(&mut self, span: Span, tokens: TokenStream) -> syn::Result<()> {
let mut tokens = tokens.into_iter();
let ident = match tokens.next() {
Some(TokenTree::Ident(i)) => i,
Some(t) => return Err(syn::Error::new_spanned(t, "expected ident")),
None => return Err(syn::Error::new(span, "expected ident to follow")),
};
match ident.to_string().as_ref() {
"prefix" => self.prefix = Some(parse_type(ident.span(), tokens)?),
"suffix" => self.suffix = Some(parse_type(ident.span(), tokens)?),
"parser" => self.parser = Some(parse_type(ident.span(), tokens)?),
"inner_parser" => self.vec.parser = Some(parse_type(ident.span(), tokens)?),
_ => return Err(syn::Error::new_spanned(ident, "unknown parameter")),
}
Ok(())
}
}