This repository has been archived on 2024-07-25. You can view files and clone it, but cannot push or open issues or pull requests.
enve/itconfig-macro/src/expand.rs

170 lines
4.7 KiB
Rust
Raw Normal View History

2020-03-12 23:20:34 +03:00
use crate::ast::*;
use quote::{quote, ToTokens, TokenStreamExt};
use proc_macro2::TokenStream as TokenStream2;
fn vec_to_token_stream_2<T>(input: &Vec<T>) -> Vec<TokenStream2>
where T: ToTokens
{
input.iter()
.map(|ns| ns.into_token_stream())
.collect()
}
impl ToTokens for RootNamespace {
fn to_tokens(&self, tokens: &mut TokenStream2) {
let name = &self.name;
let variables = vec_to_token_stream_2(&self.variables);
let namespaces = vec_to_token_stream_2(&self.namespaces);
let init_variables = self.variables.iter()
.map(|var| {
let name = &var.name;
let var_meta = vec_to_token_stream_2(&var.meta);
quote!(
#(#var_meta)*
#name();
)
})
.collect::<Vec<TokenStream2>>();
let init_namespaces = self.namespaces.iter()
.map(|ns| {
let name = &ns.name;
let ns_meta = vec_to_token_stream_2(&ns.meta);
quote!(
#(#ns_meta)*
#name::init();
)
})
.collect::<Vec<TokenStream2>>();
let inner_meta: Vec<TokenStream2> = if name.is_none() {
vec![]
} else if self.meta.is_empty() {
vec![quote!(#![allow(non_snake_case)])]
} else {
vec_to_token_stream_2(&self.meta)
};
let inner_rules = quote! {
#(#inner_meta)*
#(#namespaces)*
#(#variables)*
pub fn init() {
#(#init_variables)*
#(#init_namespaces)*
}
};
tokens.append_all(
match self.name.as_ref() {
None => inner_rules,
Some(name) => quote! {
pub mod #name {
#inner_rules
}
}
}
);
}
}
impl ToTokens for Namespace {
fn to_tokens(&self, tokens: &mut TokenStream2) {
let name = &self.name;
let variables = vec_to_token_stream_2(&self.variables);
let namespaces = vec_to_token_stream_2(&self.namespaces);
let meta = vec_to_token_stream_2(&self.meta);
let init_variables = self.variables.iter()
.map(|var| {
let name = &var.name;
let var_meta = vec_to_token_stream_2(&var.meta);
quote!(
#(#var_meta)*
#name();
)
})
.collect::<Vec<TokenStream2>>();
let init_namespaces = self.namespaces.iter()
.map(|ns| {
let name = &ns.name;
let ns_meta = vec_to_token_stream_2(&ns.meta);
quote!(
#(#ns_meta)*
#name::init();
)
})
.collect::<Vec<TokenStream2>>();
tokens.append_all(quote!(
#(#meta)*
pub mod #name {
#(#namespaces)*
#(#variables)*
pub fn init() {
#(#init_variables)*
#(#init_namespaces)*
}
}
))
}
}
impl ToTokens for Variable {
fn to_tokens(&self, tokens: &mut TokenStream2) {
let ty = &self.ty;
let name = &self.name;
let env_name = &self.env_name.clone()
.unwrap_or(name.to_string().to_uppercase());
let meta = vec_to_token_stream_2(&self.meta);
let get_variable: TokenStream2 = if self.concat_parts.is_some() {
let concat_parts = self.concat_parts.as_ref().unwrap();
quote! {{
let value_parts: Vec<String> = vec!(#(#concat_parts),*);
let value = value_parts.join("");
::std::env::set_var(#env_name, value.as_str());
value
}}
} else if self.initial.is_some() {
let initial = self.initial.as_ref().unwrap();
quote!(::itconfig::get_env_or_set_default(#env_name, #initial))
} else {
quote!(::itconfig::get_env_or_panic(#env_name))
};
if self.is_static {
tokens.append_all(quote!(
#(#meta)*
pub fn #name() -> #ty {
::lazy_static::lazy_static! {
static ref #name: #ty = #get_variable;
}
(*#name).clone()
}
));
} else {
tokens.append_all(quote!(
#(#meta)*
pub fn #name() -> #ty {
#get_variable
}
));
}
}
}