123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- mod yaml_def;
- use proc_macro::TokenStream;
- use quote::{quote};
- use syn::{LitStr, Type};
- use proc_macro_error::{proc_macro_error, abort_call_site};
- use crate::yaml_def::{Function};
- extern crate syn;
- extern crate std;
- #[proc_macro]
- #[proc_macro_error]
- pub fn generate_wasi_import(input: TokenStream) -> TokenStream{
- let ast = syn::parse_macro_input!(input as LitStr);
- let yaml_path = ast.value();
- let yaml_content = match std::fs::read_to_string(&yaml_path) {
- Ok(content) => content,
- Err(err) => {
- abort_call_site! {
- "Failed to read YAML file: {}", err;
- note = "check YAML file path: {}", yaml_path;
- }
- }
- };
- let yaml_root: yaml_def::YamlRoot = match serde_yaml::from_str(&yaml_content) {
- Ok(root) => root,
- Err(err) => {
- abort_call_site! {
- "Failed to parse YAML file: {}", err;
- note = "check YAML file syntax";
- }
- }
- };
- let modules = yaml_root.iter().map(|i| {
- let mod_name = i.0;
- let mod_val = i.1;
- let fns_result = mod_val.iter().map(|j| {
- let fn_name = j.0;
- let fn_val = j.1;
- let fn_efid = &fn_val.efid;
- let fn_efid_ident = syn::Ident::new(fn_efid, proc_macro2::Span::call_site());
- let fn_params = process_fn_signature_param(fn_val, mod_name, fn_name);
- let fn_results = process_fn_signature_results(fn_val, mod_name, fn_name);
- let fn_retval = match fn_results {
- Some(s) => {
- quote! {
- -> #s
- }
- },
- None => {
- proc_macro2::TokenStream::new()
- }
- };
- quote! {
- #[doc = #fn_name ]
- fn #fn_efid_ident(#fn_params) #fn_retval;
- }
- });
- quote! {
- #[link(wasm_import_module = #mod_name)]
- extern "C" {
- #(#fns_result)*
- }
- }
- });
- let module_wraps = yaml_root.iter().map(|i| {
- let mod_name = i.0;
- let mod_name_ident = syn::Ident::new(mod_name, proc_macro2::Span::call_site());
- let mod_val = i.1;
- let fns_result = mod_val.iter().map(|j| {
- let fn_name = j.0;
- let fn_val = j.1;
- let fn_efid = &fn_val.efid;
- let fn_name_ident = syn::Ident::new(fn_name, proc_macro2::Span::call_site());
- let fn_efid_ident = syn::Ident::new(fn_efid, proc_macro2::Span::call_site());
- let fn_params = process_fn_signature_param(fn_val, mod_name, fn_name);
- let fn_call_params = process_fn_call_param(fn_val);
- let fn_results = process_fn_signature_results(fn_val, mod_name, fn_name);
- let fn_retval = match fn_results {
- Some(s) => {
- quote! {
- -> #s
- }
- },
- None => {
- proc_macro2::TokenStream::new()
- }
- };
- quote! {
- pub unsafe fn #fn_name_ident(#fn_params) #fn_retval {
- crate::raw_fn::#fn_efid_ident(#fn_call_params)
- }
- }
- });
- quote! {
- pub mod #mod_name_ident {
- #(#fns_result)*
- }
- }
- });
- let result = quote! {
- #(#modules)*
- #(#module_wraps)*
- };
- result.into()
- }
- fn process_fn_signature_param(input: &Function, mod_name: &str, fn_name: &str) -> proc_macro2::TokenStream {
- match &input.params {
- Some(s) => {
- if s.len() == 0 {
- return proc_macro2::TokenStream::new();
- }
- let params_iter = s.iter().map(|i| {
- let param_name = &i.name;
- let param_name_ident = syn::Ident::new(¶m_name, proc_macro2::Span::call_site());
- let is_use_xtyp;
- let param_type = match &i.xtyp {
- Some(s) => {
- if s.as_str() == "enum" {
- is_use_xtyp = false;
- &i.rtype
- }else{
- is_use_xtyp = true;
- s
- }
- },
- None => {
- is_use_xtyp = false;
- &i.rtype
- }
- };
- let param_type_parse_res = syn::parse_str::<Type>(param_type.as_str());
- let param_type_ast = match param_type_parse_res {
- Ok(ast) => ast,
- Err(err) => {
- let fn_fullname = format!("{}::{}", mod_name, fn_name);
- let p_src = if is_use_xtyp {"xtyp"}else{"type"};
- let yaml_field_path = format!("{}.{}.{}.{}", mod_name, fn_name, param_name, p_src);
- abort_call_site! {
- "Failed to read param {} of {}: '{}': {}", p_src, fn_fullname, param_type, err;
- note = "Syntax error of this yaml field: {}", yaml_field_path;
- }
- }
- };
- quote!(#param_name_ident: #param_type_ast)
- });
- quote! {
- #(#params_iter),*
- }
- },
- None => {
- proc_macro2::TokenStream::new()
- }
- }
- }
- fn process_fn_call_param(input: &Function) -> proc_macro2::TokenStream {
- match &input.params {
- Some(s) => {
- if s.len() == 0 {
- return proc_macro2::TokenStream::new();
- }
- let params_iter = s.iter().map(|i| {
- let param_name = &i.name;
- syn::Ident::new(¶m_name, proc_macro2::Span::call_site())
- });
- quote! {
- #(#params_iter),*
- }
- },
- None => {
- proc_macro2::TokenStream::new()
- }
- }
- }
- fn process_fn_signature_results(input: &Function, mod_name: &str, fn_name: &str) -> Option<proc_macro2::TokenStream> {
- match &input.results {
- Some(s) => {
- if s.len() == 0 {
- return None;
- }
- let mut results_iter = s.iter().map(|i| {
- let is_use_xtyp;
- let result_type = match &i.xtyp {
- Some(s) => {
- if s.as_str() == "enum" {
- is_use_xtyp = false;
- &i.rtype
- }else{
- is_use_xtyp = true;
- s
- }
- },
- None => {
- is_use_xtyp = false;
- &i.rtype
- }
- };
- let result_type_parse_res = syn::parse_str::<Type>(result_type.as_str());
- let result_type_ast = match result_type_parse_res {
- Ok(ast) => ast,
- Err(err) => {
- let fn_fullname = format!("{}::{}", mod_name, fn_name);
- let p_src = if is_use_xtyp {"xtyp"}else{"type"};
- let yaml_field_path = format!("{}.{}.{}.{}", mod_name, fn_name, &i.name, p_src);
- abort_call_site! {
- "Failed to read result {} of {}: '{}': {}", p_src, fn_fullname, result_type, err;
- note = "Syntax error of this yaml field: {}", yaml_field_path;
- }
- }
- };
- result_type_ast
- });
- Some(if results_iter.len() == 1 {
- let result_res = results_iter.next();
- let result = match result_res {
- Some(s) => s,
- None => {
- abort_call_site! {
- "iter error in {}::{}: there should be one result in iter but got none.", mod_name, fn_name;
- note = "This is macro bug. Please report it.";
- }
- }
- };
- quote! {
- #result
- }
- }else{
- quote! {
- (#(#results_iter),*)
- }
- })
- },
- None => {
- None
- }
- }
- }
|