use std::iter;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use crate::{
macros::config::trixy::TrixyConfig,
parser::command_spec::{Enumeration, Identifier, Namespace, Structure, Type, Variant},
};
impl Namespace {
pub fn to_c(&self, config: &TrixyConfig, namespaces: &Vec<&Identifier>) -> TokenStream2 {
let mut namespaces = namespaces.clone();
if self.name.variant != Variant::RootNamespace {
namespaces.push(&self.name);
} else {
assert_eq!(namespaces.len(), 0);
}
let functions: TokenStream2 = self
.functions
.iter()
.map(|r#fn| r#fn.to_c(&config, &namespaces))
.collect();
let additional_functions: TokenStream2 = self
.namespaces
.iter()
.map(|nasp| nasp.to_c(&config, &namespaces))
.collect();
let structures: TokenStream2 = self.structures.iter().map(Structure::to_c).collect();
let enumerations: TokenStream2 = self.enumerations.iter().map(Enumeration::to_c).collect();
let all_results_types: TokenStream2 = self
.select_types_pred(|(identifier, _generic_args)| identifier.name.as_str() == "Result")
.iter()
.map(|(ident, generics)| Type::to_c_result(&ident, &generics))
.collect();
let all_option_types: TokenStream2 = self
.select_types_pred(|(identifier, _generic_args)| identifier.name.as_str() == "Option")
.iter()
.map(|(ident, generics)| Type::to_c_option(&ident, &generics))
.collect();
let all_vector_types: TokenStream2 = self
.select_types_pred(|(identifier, _generic_args)| identifier.name.as_str() == "Vec")
.iter()
.map(|(ident, generics)| Type::to_c_vector(&ident, &generics))
.collect();
if self.name.variant == Variant::RootNamespace {
quote! {
#all_results_types
#all_option_types
#all_vector_types
#enumerations
#structures
#additional_functions
#functions
}
} else {
let ident = &self.name.to_c();
quote! {
pub mod #ident {
#all_results_types
#all_option_types
#all_vector_types
#enumerations
#structures
#additional_functions
}
#functions
}
}
}
pub fn select_types_pred(
&self,
pred: fn(&(Identifier, Vec<Type>)) -> bool,
) -> Vec<(Identifier, Vec<Type>)> {
fn filter_type(ty: &Type) -> Vec<(Identifier, Vec<Type>)> {
match ty {
Type::Typical {
identifier,
generic_args,
} => {
let mut output = vec![];
output.extend(generic_args.iter().map(|ga| filter_type(ga)).flatten());
output.push((identifier.to_owned(), generic_args.to_owned()));
output
}
Type::Function { inputs, output } => {
let mut full_output = vec![];
full_output.extend(
inputs
.iter()
.map(|na| &na.r#type)
.map(|ty| filter_type(&ty))
.flatten(),
);
if let Some(out) = output {
full_output.extend(filter_type(out))
}
full_output
}
}
}
let all_types = self.collect_types();
let all_result_types: Vec<_> = all_types
.iter()
.map(|r#type| filter_type(r#type))
.flatten()
.filter(pred)
.collect();
all_result_types
}
pub fn collect_types(&self) -> Vec<Type> {
let structures_types = self
.structures
.iter()
.map(|st| st.contents.iter().map(|dc| dc.r#type.clone()))
.flatten();
self.functions
.iter()
.map(|r#fn| {
r#fn.inputs
.iter()
.map(|nt| Some(nt.r#type.clone()))
.chain({
if let Some(output) = &r#fn.output {
iter::once(Some(output.clone()))
} else {
iter::once(None)
}
})
.filter_map(|x| x)
})
.flatten()
.chain(structures_types)
.collect()
}
}