use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use crate::parser::command_spec::{Attribute, Function, Identifier, NamedType, Type};
impl Function {
pub fn to_auxiliary_c(&self, namespaces: &[&Identifier]) -> String {
let doc_comments: String = Attribute::to_auxiliary_c_merged(&self.attributes);
let ident = self.identifier.to_c_with_path(namespaces);
let inputs: Vec<TokenStream2> = self
.inputs
.iter()
.filter_map(|a| NamedType::to_auxiliary_c(a))
.collect();
let function_output = if let Some(out) = &self.output {
if Type::is_void(self.output.as_ref()) {
TokenStream2::default()
} else {
let type_name = &out.to_auxiliary_c(true, None);
let comma = if !inputs.is_empty() {
quote! {
,
}
} else {
TokenStream2::default()
};
quote! {
#type_name trixy_output #comma
}
}
} else {
TokenStream2::default()
};
let output = quote! {
extern int #ident(#function_output #(#inputs),*);
};
format!("{}{}\n", doc_comments, output)
}
pub fn to_auxiliary_c_namespace_init(&self, namespaces: &[&Identifier]) -> TokenStream2 {
let ident = &self.identifier.to_rust();
let full_ident = &self.identifier.to_c_with_path(namespaces);
quote! {
. #ident = #full_ident,
}
}
pub fn to_auxiliary_c_typedef(&self) -> TokenStream2 {
let ident = self.identifier.to_rust();
let (output, output_comma) = if let Some(output) = &self.output {
let output = output.to_auxiliary_c(true, None);
(quote! { #output }, quote! {,})
} else {
(TokenStream2::default(), TokenStream2::default())
};
let initial_inputs: Vec<TokenStream2> = self
.inputs
.iter()
.map(|named_type| (&named_type.r#type, &named_type.name))
.filter_map(|(r#type, name)| r#type.to_auxiliary_c(false, Some(name)))
.collect();
let inputs: TokenStream2 = if self.inputs.is_empty() && output.is_empty() {
quote! { void }
} else if !self.inputs.is_empty() && !output.is_empty() {
quote! {
#output_comma #(#initial_inputs),*
}
} else {
quote! {
#(#initial_inputs),*
}
};
quote! {
int (* #ident ) (#output #inputs);
}
}
}