Skip to main content

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