extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
#[proc_macro]
pub fn parse_static(input: TokenStream) -> TokenStream {
let input = get_input_string(input);
expand_static(
&fumola::check::parse(&input).expect("Parse error"),
"::fumola::ast::Prog",
)
}
fn expand_static<'de, T: Sized + serde::Serialize + serde::Deserialize<'de>>(
value: &T,
type_path: &'static str,
) -> TokenStream {
let serialized = fumola::proc_macro::serialize(value).expect("Serialization error");
let serialized_ast = proc_macro2::Literal::byte_string(&serialized);
let typ = syn::Type::Verbatim(type_path.parse().expect("Type parse error"));
TokenStream::from(quote! {{
struct STATIC;
impl std::ops::Deref for STATIC {
type Target = #typ;
fn deref(&self) -> &#typ {
struct _AssertSized where #typ: std::marker::Sized;
static ONCE: std::sync::Once = std::sync::Once::new();
static mut VALUE: *mut #typ = 0 as *mut #typ;
unsafe {
ONCE.call_once(|| VALUE = Box::into_raw(Box::new(
::fumola::proc_macro::deserialize::<#typ>(#serialized_ast).expect("Deserialization error")
)));
&*VALUE
}
}
};
&*STATIC
}})
}
fn get_input_string(input: TokenStream) -> String {
syn::parse::<syn::LitStr>(input)
.expect("Unexpected macro input")
.value()
}