1 | use proc_macro2::{Ident, Literal, TokenStream}; |
2 | use quote::{format_ident, quote}; |
3 | use syn::fold::{fold_fn_arg, fold_signature, Fold}; |
4 | use syn::parse::{Parse, ParseStream, Result}; |
5 | use syn::punctuated::Punctuated; |
6 | use syn::{Block, FnArg, Signature, Token, Visibility}; |
7 | |
8 | pub struct ArgLength { |
9 | pub length: Literal, |
10 | } |
11 | |
12 | impl Parse for ArgLength { |
13 | fn parse(input: ParseStream) -> Result<Self> { |
14 | let vars: Punctuated = Punctuated::<Literal, Token![,]>::parse_terminated(input)?; |
15 | Ok(ArgLength { |
16 | length: varsOption |
17 | .first() |
18 | .cloned() |
19 | .unwrap_or_else(|| Literal::usize_unsuffixed(0)), |
20 | }) |
21 | } |
22 | } |
23 | |
24 | pub struct JsFunction { |
25 | pub args: Vec<FnArg>, |
26 | pub name: Option<Ident>, |
27 | pub signature: Option<Signature>, |
28 | pub signature_raw: Option<Signature>, |
29 | pub block: Vec<Block>, |
30 | pub visibility: Visibility, |
31 | } |
32 | |
33 | impl JsFunction { |
34 | pub fn new() -> Self { |
35 | JsFunction { |
36 | args: vec![], |
37 | name: None, |
38 | signature: None, |
39 | signature_raw: None, |
40 | visibility: Visibility::Inherited, |
41 | block: vec![], |
42 | } |
43 | } |
44 | } |
45 | |
46 | impl Fold for JsFunction { |
47 | fn fold_fn_arg(&mut self, arg: FnArg) -> FnArg { |
48 | self.args.push(arg.clone()); |
49 | fold_fn_arg(self, arg) |
50 | } |
51 | |
52 | fn fold_signature(&mut self, signature: Signature) -> Signature { |
53 | self.name = Some(format_ident!(" {}" , signature.ident)); |
54 | let mut new_signature = signature.clone(); |
55 | new_signature.ident = format_ident!("_generated_ {}_generated_" , signature.ident); |
56 | self.signature = Some(new_signature); |
57 | self.signature_raw = Some(signature.clone()); |
58 | fold_signature(self, signature) |
59 | } |
60 | |
61 | fn fold_visibility(&mut self, v: Visibility) -> Visibility { |
62 | self.visibility = v.clone(); |
63 | v |
64 | } |
65 | |
66 | fn fold_block(&mut self, node: Block) -> Block { |
67 | self.block.push(node.clone()); |
68 | node |
69 | } |
70 | } |
71 | pub enum FunctionKind { |
72 | Contextless, |
73 | JsFunction, |
74 | } |
75 | |
76 | pub fn get_execute_js_code(new_fn_name: Ident, function_kind: FunctionKind) -> TokenStream { |
77 | let return_token_stream = match function_kind { |
78 | FunctionKind::Contextless => { |
79 | quote! { |
80 | Ok(Some(v)) => unsafe { v.raw() }, |
81 | Ok(None) => ptr::null_mut(), |
82 | } |
83 | } |
84 | FunctionKind::JsFunction => { |
85 | quote! { |
86 | Ok(v) => unsafe { v.raw() }, |
87 | } |
88 | } |
89 | }; |
90 | quote! { |
91 | match panic::catch_unwind(AssertUnwindSafe(move || #new_fn_name(ctx))).map_err(|e| { |
92 | let message = { |
93 | if let Some(string) = e.downcast_ref::<String>() { |
94 | string.clone() |
95 | } else if let Some(string) = e.downcast_ref::<&str>() { |
96 | string.to_string() |
97 | } else { |
98 | format!("panic from Rust code: {:?}" , e) |
99 | } |
100 | }; |
101 | Error::from_reason(message) |
102 | }).and_then(|v| v) { |
103 | #return_token_stream |
104 | Err(e) => { |
105 | unsafe { napi::JsError::from(e).throw_into(raw_env) }; |
106 | ptr::null_mut() |
107 | } |
108 | } |
109 | } |
110 | } |
111 | |