use crate::fce_ast_types;
use crate::new_ident;
use crate::parsed_type::*;
use proc_macro2::TokenStream;
use quote::quote;
impl quote::ToTokens for fce_ast_types::AstExternModItem {
fn to_tokens(&self, tokens: &mut TokenStream) {
crate::prepare_global_data!(
ExternMod,
self,
self.namespace,
data,
data_size,
global_static_name,
section_name
);
let wasm_import_module_name = &self.namespace;
let original = &self.original;
let generated_imports = generate_extern_section_items(&self);
let wrapper_functions = generate_wrapper_functions(&self);
let glue_code = quote! {
#[link(wasm_import_module = #wasm_import_module_name)]
#[cfg(target_arch = "wasm32")]
extern "C" {
#generated_imports
}
#[cfg(not(target_arch = "wasm32"))]
#original
#wrapper_functions
#[cfg(target_arch = "wasm32")]
#[doc(hidden)]
#[allow(clippy::all)]
#[link_section = #section_name]
pub static #global_static_name: [u8; #data_size] = { *#data };
};
tokens.extend(glue_code);
}
}
fn generate_extern_section_items(extern_item: &fce_ast_types::AstExternModItem) -> TokenStream {
let mut token_stream = TokenStream::new();
for import in &extern_item.imports {
let signature = &import.signature;
let FnEpilogDescriptor { fn_return_type, .. } = signature.output_type.generate_fn_epilog();
let link_name = import.link_name.as_ref().unwrap_or(&signature.name);
let import_name = generate_import_name(&signature.name);
let ExternDescriptor {
raw_arg_names,
raw_arg_types,
} = signature.arguments.generate_extern_prolog();
let func = quote! {
#[link_name = #link_name]
fn #import_name(#(#raw_arg_names: #raw_arg_types),*) #fn_return_type;
};
token_stream.extend(func);
}
token_stream
}
#[rustfmt::skip]
fn generate_import_name(import_name: &str) -> syn::Ident {
crate::new_ident!(format!("{}_{}", super::GENERATED_WRAPPER_FUNC_PREFIX, import_name))
}
fn generate_wrapper_functions(extern_item: &fce_ast_types::AstExternModItem) -> TokenStream {
let mut token_stream = TokenStream::new();
for import in &extern_item.imports {
let signature = &import.signature;
let visibility = &signature.visibility;
let func_name = new_ident!(&signature.name);
let return_type = signature.output_type.generate_wrapper_return_type();
let import_func_name = generate_import_name(&signature.name);
let WrapperDescriptor {
arg_names,
arg_types,
raw_args,
arg_transforms,
arg_drops,
} = signature.arguments.generate_wrapper_prolog();
let FnEpilogDescriptor {
return_expression, ..
} = signature.output_type.generate_fn_epilog();
let epilog = signature.output_type.generate_wrapper_epilog();
let wrapper_func = quote! {
#[cfg(target_arch = "wasm32")]
#[doc(hidden)]
#[allow(clippy::all)]
#visibility unsafe fn #func_name(#(#arg_names: #arg_types), *) #return_type {
#arg_transforms
#return_expression #import_func_name(#(#raw_args), *);
#arg_drops
#epilog
}
};
token_stream.extend(wrapper_func);
}
token_stream
}