use proc_macro::TokenStream;
use proc_macro_error2::{proc_macro_error};
use quote::quote;
mod fluent;
mod macro_impl;
#[proc_macro_attribute]
#[proc_macro_error]
pub fn localize(attribute: TokenStream, item: TokenStream) -> TokenStream {
let attribute_stream = proc_macro2::TokenStream::from(attribute);
let derive_input_stream = proc_macro2::TokenStream::from(item);
match macro_impl::localize(attribute_stream.clone(), derive_input_stream.clone()) {
Ok(implementation) => {
// No errors found, emit the generated `fluent_embed::Localize` implementation
let token_stream = quote! {
#derive_input_stream
#implementation
};
// Optionally expand the macro for debugging purposes if the "expand" feature is enabled
#[cfg(feature = "expand")]
{
expander::Expander::new("fluent_embed_derive")
.write_to_out_dir(token_stream)
.unwrap()
}
#[cfg(not(feature = "expand"))]
token_stream
}
Err(error) => {
// Emit the relevant error message
macro_impl::error::emit(error, attribute_stream, derive_input_stream.clone());
// Generate a minimal `Localize` implementation so the error is self-contained
match syn::parse2::<syn::DeriveInput>(derive_input_stream.clone()) {
Ok(derive_input) => {
let ident = derive_input.ident;
quote! {
#derive_input_stream
impl<W: ::std::io::Write> ::fluent_embed::Localize<W> for #ident {
const CANONICAL_LOCALE: ::fluent_embed::icu_locale::LanguageIdentifier =
::fluent_embed::icu_locale::langid!("en-US");
fn available_locales(&self) -> Vec<::fluent_embed::icu_locale::LanguageIdentifier> {
unimplemented!("Encountered error in derive macro")
}
fn message_for_locale(
&self,
writer: &mut W,
locale: &::fluent_embed::icu_locale::LanguageIdentifier,
) -> Result<(), ::fluent_embed::LocalizationError> {
unimplemented!("Encountered error in derive macro")
}
}
}
},
// Unable to fail gracefully if the ident is unknown, so just return the original input
Err(_) => derive_input_stream,
}
}
}
.into()
}