rbatis_codegen/codegen/
func.rs

1use crate::error::Error;
2use proc_macro2::{Ident, Span};
3use quote::quote;
4use quote::ToTokens;
5use syn::{BinOp, Expr, Lit, Member};
6
7///translate like `#{a + b}` Expr to rust code Expr
8fn translate(context: &str, arg: Expr, ignore: &[String]) -> Result<Expr, Error> {
9    match arg {
10        Expr::Path(b) => {
11            let token = b.to_token_stream().to_string();
12            if token == "null" {
13                return syn::parse_str::<Expr>("rbs::Value::Null").map_err(|e| Error::from(e));
14            }
15            if token == "sql" {
16                return Ok(Expr::Path(b));
17            }
18            let param = b.to_token_stream().to_string().trim().to_string();
19            let mut fetch_from_arg = true;
20            for x in ignore {
21                if param.eq(x) {
22                    fetch_from_arg = false;
23                }
24            }
25            if fetch_from_arg {
26                syn::parse_str::<Expr>(&format!("&arg[\"{}\"]", param)).map_err(|e| Error::from(e))
27            } else {
28                syn::parse_str::<Expr>(&format!("{}", param)).map_err(|e| Error::from(e))
29            }
30        }
31        Expr::MethodCall(mut b) => {
32            //receiver is named need to convert to arg["xxx"]
33            b.receiver = Box::new(translate(context, *b.receiver, ignore)?);
34            Ok(Expr::MethodCall(b))
35        }
36        Expr::Binary(mut b) => {
37            b.left = Box::new(translate(context, *b.left, ignore)?);
38            b.right = Box::new(translate(context, *b.right, ignore)?);
39            match b.op {
40                BinOp::Add(_) => {
41                    let left_token = b.left.to_token_stream().to_string();
42                    if left_token.trim().ends_with("\"") && left_token.trim().starts_with("\"") {
43                        return syn::parse_str::<Expr>(&format!(
44                            "(String::from({})).op_add({})",
45                            b.left.to_token_stream(),
46                            b.right.to_token_stream()
47                        ))
48                        .map_err(|e| Error::from(e));
49                    } else {
50                        return syn::parse_str::<Expr>(&format!(
51                            "({}).op_add(&{})",
52                            b.left.to_token_stream(),
53                            b.right.to_token_stream()
54                        ))
55                        .map_err(|e| Error::from(e));
56                    }
57                }
58                BinOp::And(_) => {
59                    b.left = Box::new(
60                        syn::parse_str::<Expr>(&format!(
61                            "bool::op_from({})",
62                            b.left.to_token_stream().to_string().trim()
63                        ))
64                        .expect("codegen_func fail"),
65                    );
66                    b.right = Box::new(
67                        syn::parse_str::<Expr>(&format!(
68                            "bool::op_from({})",
69                            b.right.to_token_stream().to_string().trim()
70                        ))
71                        .expect("codegen_func fail"),
72                    );
73                }
74                BinOp::Or(_) => {
75                    b.left = Box::new(
76                        syn::parse_str::<Expr>(&format!(
77                            "bool::op_from({})",
78                            b.left.to_token_stream().to_string().trim()
79                        ))
80                        .expect("codegen_func fail"),
81                    );
82                    b.right = Box::new(
83                        syn::parse_str::<Expr>(&format!(
84                            "bool::op_from({})",
85                            b.right.to_token_stream().to_string().trim()
86                        ))
87                        .expect("codegen_func fail"),
88                    );
89                }
90
91                // The `-` operator (subtraction)
92                BinOp::Sub(_) => {
93                    return syn::parse_str::<Expr>(&format!(
94                        "({}).op_sub(&{})",
95                        b.left.to_token_stream(),
96                        b.right.to_token_stream()
97                    ))
98                    .map_err(|e| Error::from(e));
99                }
100                // The `*` operator (multiplication)
101                BinOp::Mul(_) => {
102                    return syn::parse_str::<Expr>(&format!(
103                        "({}).op_mul(&{})",
104                        b.left.to_token_stream(),
105                        b.right.to_token_stream()
106                    ))
107                    .map_err(|e| Error::from(e));
108                }
109                // The `/` operator (division)
110                BinOp::Div(_) => {
111                    return syn::parse_str::<Expr>(&format!(
112                        "({}).op_div(&{})",
113                        b.left.to_token_stream(),
114                        b.right.to_token_stream()
115                    ))
116                    .map_err(|e| Error::from(e));
117                }
118                // The `%` operator (modulus)
119                BinOp::Rem(_) => {
120                    return syn::parse_str::<Expr>(&format!(
121                        "({}).op_rem(&{})",
122                        b.left.to_token_stream(),
123                        b.right.to_token_stream()
124                    ))
125                    .map_err(|e| Error::from(e));
126                }
127                // The `&` operator (bitwise and)
128                BinOp::BitAnd(_) => {
129                    return syn::parse_str::<Expr>(&format!(
130                        "({}).op_bitand(&{})",
131                        b.left.to_token_stream(),
132                        b.right.to_token_stream()
133                    ))
134                    .map_err(|e| Error::from(e));
135                }
136                // The `|` operator (bitwise or)
137                BinOp::BitOr(_) => {
138                    return syn::parse_str::<Expr>(&format!(
139                        "({}).op_bitor(&{})",
140                        b.left.to_token_stream(),
141                        b.right.to_token_stream()
142                    ))
143                    .map_err(|e| Error::from(e));
144                }
145                // The `==` operator (equality)
146                BinOp::Eq(_) => {
147                    return syn::parse_str::<Expr>(&format!(
148                        "({}).op_eq(&{})",
149                        b.left.to_token_stream(),
150                        b.right.to_token_stream()
151                    ))
152                    .map_err(|e| Error::from(e));
153                }
154                // The `<` operator (less than)
155                BinOp::Lt(_) => {
156                    return syn::parse_str::<Expr>(&format!(
157                        "({}).op_lt(&{})",
158                        b.left.to_token_stream(),
159                        b.right.to_token_stream()
160                    ))
161                    .map_err(|e| Error::from(e));
162                }
163                // The `<=` operator (less than or equal to)
164                BinOp::Le(_) => {
165                    return syn::parse_str::<Expr>(&format!(
166                        "({}).op_le(&{})",
167                        b.left.to_token_stream(),
168                        b.right.to_token_stream()
169                    ))
170                    .map_err(|e| Error::from(e));
171                }
172                // The `!=` operator (not equal to)
173                BinOp::Ne(_) => {
174                    return syn::parse_str::<Expr>(&format!(
175                        "({}).op_ne(&{})",
176                        b.left.to_token_stream(),
177                        b.right.to_token_stream()
178                    ))
179                    .map_err(|e| Error::from(e));
180                }
181                // The `>=` operator (greater than or equal to)
182                BinOp::Ge(_) => {
183                    return syn::parse_str::<Expr>(&format!(
184                        "({}).op_ge(&{})",
185                        b.left.to_token_stream(),
186                        b.right.to_token_stream()
187                    ))
188                    .map_err(|e| Error::from(e));
189                }
190                // The `>` operator (greater than)
191                BinOp::Gt(_) => {
192                    return syn::parse_str::<Expr>(&format!(
193                        "({}).op_gt(&{})",
194                        b.left.to_token_stream(),
195                        b.right.to_token_stream()
196                    ))
197                    .map_err(|e| Error::from(e));
198                }
199                // The `^` operator (bitwise xor)
200                BinOp::BitXor(_) => {
201                    return syn::parse_str::<Expr>(&format!(
202                        "({}).op_bitxor(&{})",
203                        b.left.to_token_stream(),
204                        b.right.to_token_stream()
205                    ))
206                    .map_err(|e| Error::from(e));
207                }
208                // The `<<` operator (shift left)
209                _ => {
210                    return Err(Error::from(format!(
211                        "unsupported token {}",
212                        b.op.to_token_stream()
213                    )))
214                }
215            }
216            Ok(Expr::Binary(b))
217        }
218        Expr::Unary(mut b) => {
219            b.expr = Box::new(translate(context, *b.expr, ignore)?);
220            if b.op.to_token_stream().to_string().trim() == "-" {
221                return syn::parse_str::<Expr>(&format!(
222                    "0i64.op_sub({})",
223                    b.expr.to_token_stream().to_string().trim()
224                ))
225                .map_err(|e| Error::from(e));
226            }
227            if b.op.to_token_stream().to_string().trim() == "!" {
228                b.expr = Box::new(
229                    syn::parse_str::<Expr>(&format!(
230                        "bool::from({})",
231                        b.expr.to_token_stream().to_string().trim()
232                    ))
233                    .map_err(|e| Error::from(e))?,
234                );
235            }
236            Ok(Expr::Unary(b))
237        }
238        //(a-b)
239        Expr::Paren(mut b) => {
240            b.expr = Box::new(translate(context, *b.expr, ignore)?);
241            Ok(Expr::Paren(b))
242        }
243        //a.b
244        Expr::Field(mut b) => {
245            b.base = Box::new(translate(context, *b.base, ignore)?);
246            match b.member {
247                Member::Named(named) => {
248                    return syn::parse_str::<Expr>(&format!(
249                        "(&{}[\"{}\"])",
250                        b.base.to_token_stream(),
251                        named.to_token_stream()
252                    ))
253                    .map_err(|e| Error::from(e));
254                }
255                Member::Unnamed(_) => {}
256            }
257            Ok(Expr::Field(b))
258        }
259        Expr::Reference(mut b) => {
260            b.expr = Box::new(translate(context, *b.expr, ignore)?);
261            let result = Expr::Reference(b);
262            Ok(result)
263        }
264        Expr::Index(mut b) => {
265            b.expr = Box::new(translate(context, *b.expr, ignore)?);
266            syn::parse_str::<Expr>(&format!(
267                "&{}[{}]",
268                b.expr.to_token_stream(),
269                b.index.to_token_stream()
270            ))
271            .map_err(|e| Error::from(e))
272        }
273        Expr::Let(_let_expr) => Err(Error::from("unsupported token `let`")),
274        Expr::Lit(b) => {
275            match b.lit {
276                Lit::Str(_) => {}
277                Lit::ByteStr(_) => {}
278                Lit::Byte(_) => {}
279                Lit::Char(_) => {}
280                Lit::Int(i) => {
281                    //cast int to i64
282                    return syn::parse_str::<Expr>(&format!("{}i64", i))
283                        .map_err(|e| Error::from(e));
284                }
285                Lit::Float(f) => {
286                    //cast int to f64
287                    return syn::parse_str::<Expr>(&format!("{}f64", f))
288                        .map_err(|e| Error::from(e));
289                }
290                Lit::Bool(_) => {}
291                Lit::Verbatim(_) => {}
292                _ => {}
293            }
294            Ok(Expr::Lit(b))
295        }
296        _ => Ok(arg),
297    }
298}
299
300/// gen method or body(if func_name_ident is empty)
301pub fn impl_fn(
302    context: &str,
303    func_name_ident: &str,
304    args: &str,
305    serialize_result: bool,
306    ignore: &[String],
307) -> proc_macro2::TokenStream {
308    let mut string_data = args.to_string();
309    string_data = string_data[1..string_data.len() - 1].to_string();
310    //convert string define
311    let mut last_char = '_';
312    let mut string_data_new = String::new();
313    for x in string_data.chars() {
314        if x == '\'' && last_char != '\\' {
315            string_data_new.push('\"');
316        } else {
317            string_data_new.push(x);
318        }
319        last_char = x;
320    }
321    string_data = string_data_new;
322    let t = syn::parse_str::<Expr>(&string_data);
323    if t.is_err() {
324        panic!(
325            "[rbatis-codegen]syn::parse_str: {} fail: {}",
326            args,
327            t.err().expect("codegen_func fail").to_string()
328        )
329    }
330    let mut t = t.expect("codegen_func fail");
331    t = translate(context, t, ignore).expect("translate fail");
332    string_data = t.to_token_stream().to_string();
333    let t = syn::parse_str::<Expr>(&string_data);
334    if t.is_err() {
335        panic!(
336            "[rbatis-codegen]syn::parse_str: {} fail: {}",
337            args,
338            t.err().expect("codegen_func fail").to_string()
339        )
340    }
341    let t = t.expect("codegen_func fail");
342    let mut result_impl = quote! { {#t} };
343    if serialize_result {
344        result_impl = quote! {rbs::value({#t}).unwrap_or_default()};
345    }
346    if func_name_ident.is_empty() || func_name_ident.eq("\"\"") {
347        quote! {#result_impl}
348    } else {
349        let func_name_ident = Ident::new(&func_name_ident.to_string(), Span::call_site());
350        quote! {
351            pub fn #func_name_ident(arg:&rbs::Value) -> rbs::Value {
352               use rbatis_codegen::ops::*;
353               #result_impl
354            }
355        }
356    }
357}