use proc_macro::TokenStream;
use proc_macro2::{Ident, Span};
use quote::quote;
use syn::{
LitStr, Result, Token,
parse::{Parse, ParseStream},
punctuated::Punctuated,
};
struct DocGenEntry {
severity: Ident,
_dot1: Token![.],
component: Ident,
_dot2: Token![.],
primary: Ident,
_dot3: Token![.],
sequence: Ident,
_arrow: Token![=>],
_bracket_open: syn::token::Bracket,
formats: Punctuated<LitStr, Token![,]>,
}
impl Parse for DocGenEntry {
fn parse(input: ParseStream) -> Result<Self> {
let severity = input.parse()?;
let _dot1 = input.parse()?;
let component = input.parse()?;
let _dot2 = input.parse()?;
let primary = input.parse()?;
let _dot3 = input.parse()?;
let sequence = input.parse()?;
let _arrow = input.parse()?;
let content;
let _bracket_open = syn::bracketed!(content in input);
let formats = Punctuated::parse_terminated(&content)?;
Ok(DocGenEntry {
severity,
_dot1,
component,
_dot2,
primary,
_dot3,
sequence,
_arrow,
_bracket_open,
formats,
})
}
}
pub fn expand(input: TokenStream) -> TokenStream {
let entry = syn::parse_macro_input!(input as DocGenEntry);
let const_name = Ident::new(
&format!(
"{}_{}_{}_{}_COMPLETE",
entry.severity.to_string().to_uppercase(),
entry.component.to_string().to_uppercase(),
entry.primary.to_string().to_uppercase(),
entry.sequence.to_string().to_uppercase()
),
Span::call_site(),
);
let format_names: Vec<String> = entry.formats.iter().map(|lit| lit.value()).collect();
let formats_array = format_names.iter().map(|s| s.as_str());
let diagnostic_code = format!(
"{}.{}.{}.{}",
entry.severity, entry.component, entry.primary, entry.sequence
);
let registry_entry_name = Ident::new(
&format!("__DOC_GEN_ENTRY_{}", const_name.to_string().to_uppercase()),
Span::call_site(),
);
let output = quote! {
#[cfg(feature = "metadata")]
#[doc = concat!("Documentation generation entry for ", #diagnostic_code)]
pub struct #registry_entry_name;
#[cfg(feature = "metadata")]
impl #registry_entry_name {
pub fn register(registry: &mut ::waddling_errors::doc_generator::DocRegistry) {
registry.register_diagnostic_complete(&#const_name);
}
pub const fn formats() -> &'static [&'static str] {
&[#(#formats_array),*]
}
pub const fn code() -> &'static str {
#diagnostic_code
}
}
};
TokenStream::from(output)
}