rbatis_codegen/codegen/
parser_pysql.rs

1use crate::codegen::parser_html::parse_html;
2use crate::codegen::proc_macro::TokenStream;
3use crate::codegen::syntax_tree_pysql::bind_node::BindNode;
4use crate::codegen::syntax_tree_pysql::break_node::BreakNode;
5use crate::codegen::syntax_tree_pysql::choose_node::ChooseNode;
6use crate::codegen::syntax_tree_pysql::continue_node::ContinueNode;
7use crate::codegen::syntax_tree_pysql::error::Error;
8use crate::codegen::syntax_tree_pysql::foreach_node::ForEachNode;
9use crate::codegen::syntax_tree_pysql::if_node::IfNode;
10use crate::codegen::syntax_tree_pysql::otherwise_node::OtherwiseNode;
11use crate::codegen::syntax_tree_pysql::set_node::SetNode;
12use crate::codegen::syntax_tree_pysql::string_node::StringNode;
13use crate::codegen::syntax_tree_pysql::trim_node::TrimNode;
14use crate::codegen::syntax_tree_pysql::when_node::WhenNode;
15use crate::codegen::syntax_tree_pysql::where_node::WhereNode;
16use crate::codegen::syntax_tree_pysql::{DefaultName, Name, NodeType};
17use crate::codegen::ParseArgs;
18use quote::ToTokens;
19use std::collections::HashMap;
20use syn::ItemFn;
21
22pub trait ParsePySql {
23    fn parse_pysql(arg: &str) -> Result<Vec<NodeType>, Error>;
24}
25
26pub fn impl_fn_py(m: &ItemFn, args: &ParseArgs) -> TokenStream {
27    let fn_name = m.sig.ident.to_string();
28    let mut data = {
29        let mut s = String::new();
30        for x in &args.sqls {
31            s = s + &x.to_token_stream().to_string();
32        }
33        s
34    };
35    if data.ne("\"\"") && data.starts_with("\"") && data.ends_with("\"") {
36        data = data[1..data.len() - 1].to_string();
37    }
38    data = data.replace("\\n", "\n");
39    let nodes = NodeType::parse_pysql(&data).expect("[rbatis-codegen] parse py_sql fail!");
40    let htmls = crate::codegen::syntax_tree_pysql::to_html(
41        &nodes,
42        data.starts_with("select") || data.starts_with(" select"),
43        &fn_name,
44    );
45    return parse_html(&htmls, &fn_name, &mut vec![]).into();
46}
47
48impl ParsePySql for NodeType {
49    //TODO maybe this use Rust parser crates?
50    fn parse_pysql(arg: &str) -> Result<Vec<NodeType>, Error> {
51        let line_space_map = Self::create_line_space_map(&arg);
52        let mut main_node = vec![];
53        let ls = arg.lines();
54        let mut space = -1;
55        let mut line = -1;
56        let mut skip = -1;
57        for x in ls {
58            line += 1;
59            if x.is_empty() || (skip != -1 && line <= skip) {
60                continue;
61            }
62            let count_index = *line_space_map
63                .get(&line)
64                .ok_or_else(|| Error::from(format!("line_space_map not heve line:{}", line)))?;
65            if space == -1 {
66                space = count_index;
67            }
68            let (child_str, do_skip) =
69                Self::find_child_str(line, count_index, arg, &line_space_map);
70            if do_skip != -1 && do_skip >= skip {
71                skip = do_skip;
72            }
73            let parserd;
74            if !child_str.is_empty() {
75                parserd = Self::parse_pysql(child_str.as_str())?;
76            } else {
77                parserd = vec![];
78            }
79            Self::parse_pysql_node(
80                &mut main_node,
81                x,
82                *line_space_map
83                    .get(&line)
84                    .ok_or_else(|| Error::from(format!("line:{} not exist!", line)))?
85                    as usize,
86                parserd,
87            )?;
88        }
89        return Ok(main_node);
90    }
91}
92
93impl NodeType {
94    fn parse_pysql_node(
95        main_node: &mut Vec<NodeType>,
96        x: &str,
97        space: usize,
98        mut childs: Vec<NodeType>,
99    ) -> Result<(), Error> {
100        let mut trim_x = x.trim();
101        if trim_x.starts_with("//") {
102            return Ok(());
103        }
104        if trim_x.ends_with(":") {
105            trim_x = trim_x[0..trim_x.len() - 1].trim();
106            if trim_x.contains(": ") {
107                let vecs: Vec<&str> = trim_x.split(": ").collect();
108                if vecs.len() > 1 {
109                    let len = vecs.len();
110                    for index in 0..len {
111                        let index = len - 1 - index;
112                        let item = vecs[index];
113                        childs = vec![Self::parse_trim_node(item, x, childs)?];
114                        if index == 0 {
115                            for x in &childs {
116                                main_node.push(x.clone());
117                            }
118                            return Ok(());
119                        }
120                    }
121                }
122            }
123            let node = Self::parse_trim_node(trim_x, x, childs)?;
124            main_node.push(node);
125            return Ok(());
126        } else {
127            //string,replace space to only one
128            let mut data;
129            if space <= 1 {
130                data = x.to_string();
131            } else {
132                data = x[(space - 1)..].to_string();
133            }
134            data = data.trim().to_string();
135            main_node.push(NodeType::NString(StringNode { value: data }));
136            for x in childs {
137                main_node.push(x);
138            }
139            return Ok(());
140        }
141    }
142
143    fn count_space(arg: &str) -> i32 {
144        let cs = arg.chars();
145        let mut index = 0;
146        for x in cs {
147            match x {
148                ' ' => {
149                    index += 1;
150                }
151                _ => {
152                    break;
153                }
154            }
155        }
156        return index;
157    }
158
159    ///find_child_str
160    fn find_child_str(
161        line_index: i32,
162        space_index: i32,
163        arg: &str,
164        m: &HashMap<i32, i32>,
165    ) -> (String, i32) {
166        let mut result = String::new();
167        let mut skip_line = -1;
168        let mut line = -1;
169        let lines = arg.lines();
170        for x in lines {
171            line += 1;
172            if line > line_index {
173                let cached_space = *m.get(&line).expect("line not exists");
174                if cached_space > space_index {
175                    result = result + x + "\n";
176                    skip_line = line;
177                } else {
178                    break;
179                }
180            }
181        }
182        return (result, skip_line);
183    }
184
185    ///Map<line,space>
186    fn create_line_space_map(arg: &str) -> HashMap<i32, i32> {
187        let mut m = HashMap::with_capacity(100);
188        let lines = arg.lines();
189        let mut line = -1;
190        for x in lines {
191            line += 1;
192            let space = Self::count_space(x);
193            //dothing
194            m.insert(line, space);
195        }
196        return m;
197    }
198
199    fn parse_trim_node(
200        trim_express: &str,
201        source_str: &str,
202        childs: Vec<NodeType>,
203    ) -> Result<NodeType, Error> {
204        if trim_express.starts_with(IfNode::name()) {
205            return Ok(NodeType::NIf(IfNode {
206                childs,
207                test: trim_express.trim_start_matches("if ").to_string(),
208            }));
209        } else if trim_express.starts_with(ForEachNode::name()) {
210            let for_tag = "for";
211            if !trim_express.starts_with(for_tag) {
212                return Err(Error::from(
213                    "[rbatis-codegen] parser express fail:".to_string() + source_str,
214                ));
215            }
216            let in_tag = " in ";
217            if !trim_express.contains(in_tag) {
218                return Err(Error::from(
219                    "[rbatis-codegen] parser express fail:".to_string() + source_str,
220                ));
221            }
222            let in_index = trim_express
223                .find(in_tag)
224                .ok_or_else(|| Error::from(format!("{} not have {}", trim_express, in_tag)))?;
225            let col = trim_express[in_index + in_tag.len()..].trim();
226            let mut item = trim_express[for_tag.len()..in_index].trim();
227            let mut index = "";
228            if item.contains(",") {
229                let splits: Vec<&str> = item.split(",").collect();
230                if splits.len() != 2 {
231                    panic!("[rbatis-codegen_codegen] for node must be 'for key,item in col:'");
232                }
233                index = splits[0];
234                item = splits[1];
235            }
236            return Ok(NodeType::NForEach(ForEachNode {
237                childs,
238                collection: col.to_string(),
239                index: index.to_string(),
240                item: item.to_string(),
241            }));
242        } else if trim_express.starts_with(TrimNode::name()) {
243            let trim_express = trim_express.trim().trim_start_matches("trim ").trim();
244            if trim_express.starts_with("'") && trim_express.ends_with("'")
245                || trim_express.starts_with("`") && trim_express.ends_with("`")
246            {
247                let mut trim_express = trim_express;
248                if trim_express.starts_with("`") && trim_express.ends_with("`") {
249                    trim_express = trim_express.trim_start_matches("`").trim_end_matches("`");
250                } else if trim_express.starts_with("'") && trim_express.ends_with("'") {
251                    trim_express = trim_express.trim_start_matches("'").trim_end_matches("'");
252                }
253                return Ok(NodeType::NTrim(TrimNode {
254                    childs,
255                    start: trim_express.to_string(),
256                    end: trim_express.to_string(),
257                }));
258            } else if trim_express.contains("=") || trim_express.contains(",") {
259                let express: Vec<&str> = trim_express.split(",").collect();
260                let mut prefix = "";
261                let mut suffix = "";
262                for mut expr in express {
263                    expr = expr.trim();
264                    if expr.starts_with("start") {
265                        prefix = expr
266                            .trim_start_matches("start")
267                            .trim()
268                            .trim_start_matches("=")
269                            .trim()
270                            .trim_start_matches("'")
271                            .trim_end_matches("'")
272                            .trim_start_matches("`")
273                            .trim_end_matches("`");
274                    } else if expr.starts_with("end") {
275                        suffix = expr
276                            .trim_start_matches("end")
277                            .trim()
278                            .trim_start_matches("=")
279                            .trim()
280                            .trim_start_matches("'")
281                            .trim_end_matches("'")
282                            .trim_start_matches("`")
283                            .trim_end_matches("`");
284                    } else {
285                        return Err(Error::from(format!("[rbatis-codegen] express trim node error, for example  trim 'value':  trim start='value': trim start='value',end='value':   express = {}", trim_express)));
286                    }
287                }
288                return Ok(NodeType::NTrim(TrimNode {
289                    childs,
290                    start: prefix.to_string(),
291                    end: suffix.to_string(),
292                }));
293            } else {
294                return Err(Error::from(format!("[rbatis-codegen] express trim node error, for example  trim 'value':  trim start='value': trim start='value',end='value':   error express = {}", trim_express)));
295            }
296        } else if trim_express.starts_with(ChooseNode::name()) {
297            let mut node = ChooseNode {
298                when_nodes: vec![],
299                otherwise_node: None,
300            };
301            for x in childs {
302                match x {
303                    NodeType::NWhen(_) => {
304                        node.when_nodes.push(x);
305                    }
306                    NodeType::NOtherwise(_) => {
307                        node.otherwise_node = Some(Box::new(x));
308                    }
309                    _ => {
310                        return Err(Error::from("[rbatis-codegen] parser node fail,choose node' child must be when and otherwise nodes!".to_string()));
311                    }
312                }
313            }
314            return Ok(NodeType::NChoose(node));
315        } else if trim_express.starts_with(OtherwiseNode::default_name())
316            || trim_express.starts_with(OtherwiseNode::name())
317        {
318            return Ok(NodeType::NOtherwise(OtherwiseNode { childs }));
319        } else if trim_express.starts_with(WhenNode::name()) {
320            let trim_express = trim_express[WhenNode::name().len()..].trim();
321            return Ok(NodeType::NWhen(WhenNode {
322                childs,
323                test: trim_express.to_string(),
324            }));
325        } else if trim_express.starts_with(BindNode::default_name())
326            || trim_express.starts_with(BindNode::name())
327        {
328            let express;
329            if trim_express.starts_with(BindNode::default_name()) {
330                express = trim_express[BindNode::default_name().len()..].trim();
331            } else {
332                express = trim_express[BindNode::name().len()..].trim();
333            }
334            let name_value: Vec<&str> = express.split("=").collect();
335            if name_value.len() != 2 {
336                return Err(Error::from(
337                    "[rbatis-codegen] parser bind express fail:".to_string() + trim_express,
338                ));
339            }
340            return Ok(NodeType::NBind(BindNode {
341                name: name_value[0].to_owned().trim().to_string(),
342                value: name_value[1].to_owned().trim().to_string(),
343            }));
344        } else if trim_express.starts_with(SetNode::name()) {
345            return Ok(NodeType::NSet(SetNode { childs }));
346        } else if trim_express.starts_with(WhereNode::name()) {
347            return Ok(NodeType::NWhere(WhereNode { childs }));
348        } else if trim_express.starts_with(ContinueNode::name()) {
349            return Ok(NodeType::NContinue(ContinueNode {}));
350        } else if trim_express.starts_with(BreakNode::name()) {
351            return Ok(NodeType::NBreak(BreakNode {}));
352        } else {
353            // unkonw tag
354            return Err(Error::from(
355                "[rbatis-codegen] unknow tag: ".to_string() + source_str,
356            ));
357        }
358    }
359}