lib.rs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. mod yaml_def;
  2. use proc_macro::TokenStream;
  3. use quote::{quote};
  4. use syn::{LitStr, Type};
  5. use proc_macro_error::{proc_macro_error, abort_call_site};
  6. use crate::yaml_def::{Function};
  7. extern crate syn;
  8. extern crate std;
  9. #[proc_macro]
  10. #[proc_macro_error]
  11. pub fn generate_wasi_import(input: TokenStream) -> TokenStream{
  12. let ast = syn::parse_macro_input!(input as LitStr);
  13. let yaml_path = ast.value();
  14. let yaml_content = match std::fs::read_to_string(&yaml_path) {
  15. Ok(content) => content,
  16. Err(err) => {
  17. abort_call_site! {
  18. "Failed to read YAML file: {}", err;
  19. note = "check YAML file path: {}", yaml_path;
  20. }
  21. }
  22. };
  23. let yaml_root: yaml_def::YamlRoot = match serde_yaml::from_str(&yaml_content) {
  24. Ok(root) => root,
  25. Err(err) => {
  26. abort_call_site! {
  27. "Failed to parse YAML file: {}", err;
  28. note = "check YAML file syntax";
  29. }
  30. }
  31. };
  32. let modules = yaml_root.iter().map(|i| {
  33. let mod_name = i.0;
  34. let mod_val = i.1;
  35. let fns_result = mod_val.iter().map(|j| {
  36. let fn_name = j.0;
  37. let fn_val = j.1;
  38. let fn_efid = &fn_val.efid;
  39. let fn_efid_ident = syn::Ident::new(fn_efid, proc_macro2::Span::call_site());
  40. let fn_params = process_fn_signature_param(fn_val, mod_name, fn_name);
  41. let fn_results = process_fn_signature_results(fn_val, mod_name, fn_name);
  42. let fn_retval = match fn_results {
  43. Some(s) => {
  44. quote! {
  45. -> #s
  46. }
  47. },
  48. None => {
  49. proc_macro2::TokenStream::new()
  50. }
  51. };
  52. quote! {
  53. #[doc = #fn_name ]
  54. fn #fn_efid_ident(#fn_params) #fn_retval;
  55. }
  56. });
  57. quote! {
  58. #[link(wasm_import_module = #mod_name)]
  59. extern "C" {
  60. #(#fns_result)*
  61. }
  62. }
  63. });
  64. let module_wraps = yaml_root.iter().map(|i| {
  65. let mod_name = i.0;
  66. let mod_name_ident = syn::Ident::new(mod_name, proc_macro2::Span::call_site());
  67. let mod_val = i.1;
  68. let fns_result = mod_val.iter().map(|j| {
  69. let fn_name = j.0;
  70. let fn_val = j.1;
  71. let fn_efid = &fn_val.efid;
  72. let fn_name_ident = syn::Ident::new(fn_name, proc_macro2::Span::call_site());
  73. let fn_efid_ident = syn::Ident::new(fn_efid, proc_macro2::Span::call_site());
  74. let fn_params = process_fn_signature_param(fn_val, mod_name, fn_name);
  75. let fn_call_params = process_fn_call_param(fn_val);
  76. let fn_results = process_fn_signature_results(fn_val, mod_name, fn_name);
  77. let fn_retval = match fn_results {
  78. Some(s) => {
  79. quote! {
  80. -> #s
  81. }
  82. },
  83. None => {
  84. proc_macro2::TokenStream::new()
  85. }
  86. };
  87. quote! {
  88. pub unsafe fn #fn_name_ident(#fn_params) #fn_retval {
  89. crate::raw_fn::#fn_efid_ident(#fn_call_params)
  90. }
  91. }
  92. });
  93. quote! {
  94. pub mod #mod_name_ident {
  95. #(#fns_result)*
  96. }
  97. }
  98. });
  99. let result = quote! {
  100. #(#modules)*
  101. #(#module_wraps)*
  102. };
  103. result.into()
  104. }
  105. fn process_fn_signature_param(input: &Function, mod_name: &str, fn_name: &str) -> proc_macro2::TokenStream {
  106. match &input.params {
  107. Some(s) => {
  108. if s.len() == 0 {
  109. return proc_macro2::TokenStream::new();
  110. }
  111. let params_iter = s.iter().map(|i| {
  112. let param_name = &i.name;
  113. let param_name_ident = syn::Ident::new(&param_name, proc_macro2::Span::call_site());
  114. let is_use_xtyp;
  115. let param_type = match &i.xtyp {
  116. Some(s) => {
  117. if s.as_str() == "enum" {
  118. is_use_xtyp = false;
  119. &i.rtype
  120. }else{
  121. is_use_xtyp = true;
  122. s
  123. }
  124. },
  125. None => {
  126. is_use_xtyp = false;
  127. &i.rtype
  128. }
  129. };
  130. let param_type_parse_res = syn::parse_str::<Type>(param_type.as_str());
  131. let param_type_ast = match param_type_parse_res {
  132. Ok(ast) => ast,
  133. Err(err) => {
  134. let fn_fullname = format!("{}::{}", mod_name, fn_name);
  135. let p_src = if is_use_xtyp {"xtyp"}else{"type"};
  136. let yaml_field_path = format!("{}.{}.{}.{}", mod_name, fn_name, param_name, p_src);
  137. abort_call_site! {
  138. "Failed to read param {} of {}: '{}': {}", p_src, fn_fullname, param_type, err;
  139. note = "Syntax error of this yaml field: {}", yaml_field_path;
  140. }
  141. }
  142. };
  143. quote!(#param_name_ident: #param_type_ast)
  144. });
  145. quote! {
  146. #(#params_iter),*
  147. }
  148. },
  149. None => {
  150. proc_macro2::TokenStream::new()
  151. }
  152. }
  153. }
  154. fn process_fn_call_param(input: &Function) -> proc_macro2::TokenStream {
  155. match &input.params {
  156. Some(s) => {
  157. if s.len() == 0 {
  158. return proc_macro2::TokenStream::new();
  159. }
  160. let params_iter = s.iter().map(|i| {
  161. let param_name = &i.name;
  162. syn::Ident::new(&param_name, proc_macro2::Span::call_site())
  163. });
  164. quote! {
  165. #(#params_iter),*
  166. }
  167. },
  168. None => {
  169. proc_macro2::TokenStream::new()
  170. }
  171. }
  172. }
  173. fn process_fn_signature_results(input: &Function, mod_name: &str, fn_name: &str) -> Option<proc_macro2::TokenStream> {
  174. match &input.results {
  175. Some(s) => {
  176. if s.len() == 0 {
  177. return None;
  178. }
  179. let mut results_iter = s.iter().map(|i| {
  180. let is_use_xtyp;
  181. let result_type = match &i.xtyp {
  182. Some(s) => {
  183. if s.as_str() == "enum" {
  184. is_use_xtyp = false;
  185. &i.rtype
  186. }else{
  187. is_use_xtyp = true;
  188. s
  189. }
  190. },
  191. None => {
  192. is_use_xtyp = false;
  193. &i.rtype
  194. }
  195. };
  196. let result_type_parse_res = syn::parse_str::<Type>(result_type.as_str());
  197. let result_type_ast = match result_type_parse_res {
  198. Ok(ast) => ast,
  199. Err(err) => {
  200. let fn_fullname = format!("{}::{}", mod_name, fn_name);
  201. let p_src = if is_use_xtyp {"xtyp"}else{"type"};
  202. let yaml_field_path = format!("{}.{}.{}.{}", mod_name, fn_name, &i.name, p_src);
  203. abort_call_site! {
  204. "Failed to read result {} of {}: '{}': {}", p_src, fn_fullname, result_type, err;
  205. note = "Syntax error of this yaml field: {}", yaml_field_path;
  206. }
  207. }
  208. };
  209. result_type_ast
  210. });
  211. Some(if results_iter.len() == 1 {
  212. let result_res = results_iter.next();
  213. let result = match result_res {
  214. Some(s) => s,
  215. None => {
  216. abort_call_site! {
  217. "iter error in {}::{}: there should be one result in iter but got none.", mod_name, fn_name;
  218. note = "This is macro bug. Please report it.";
  219. }
  220. }
  221. };
  222. quote! {
  223. #result
  224. }
  225. }else{
  226. quote! {
  227. (#(#results_iter),*)
  228. }
  229. })
  230. },
  231. None => {
  232. None
  233. }
  234. }
  235. }