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

187 lines
5.6 KiB
Rust

use crate::ast::*;
use crate::utils::{vec_to_token_stream_2, SupportedBox};
use proc_macro2::TokenStream as TokenStream2;
use quote::{quote, ToTokens, TokenStreamExt};
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_else(|| 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 let Some(initial) = &self.initial {
match self.supported_box.clone() {
Some(SupportedBox::Vec(sep)) => {
let sep = &sep.unwrap_or_else(|| String::from(","));
quote!(::itconfig::get_vec_env_or_set_default(#env_name, #sep, #initial))
}
_ => quote!(::itconfig::get_env_or_set_default(#env_name, #initial)),
}
} else {
match self.supported_box.clone() {
Some(SupportedBox::Option) => {
quote!(::itconfig::maybe_get_env(#env_name))
}
Some(SupportedBox::OptionVec(sep)) => {
let sep = &sep.unwrap_or_else(|| String::from(","));
quote!(::itconfig::maybe_get_vec_env(#env_name, #sep))
}
Some(SupportedBox::Vec(sep)) => {
let sep = &sep.unwrap_or_else(|| String::from(","));
quote!(::itconfig::get_vec_env_or_panic(#env_name, #sep))
}
None => {
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
}
));
}
}
}