rust_code_analysis/
parser.rs

1use std::marker::PhantomData;
2use std::path::Path;
3use std::sync::Arc;
4use tree_sitter::{Parser as TSParser, Tree};
5
6use crate::alterator::Alterator;
7use crate::c_macro;
8use crate::checker::*;
9use crate::getter::Getter;
10use crate::langs::*;
11use crate::node::Node;
12use crate::preproc::{get_macros, PreprocResults};
13use crate::traits::*;
14
15pub struct Parser<T: TSLanguage + Checker + Getter + Alterator + CodeMetricsT> {
16    code: Vec<u8>,
17    tree: Tree,
18    phantom: PhantomData<T>,
19}
20
21type FilterFn = dyn Fn(&Node) -> bool;
22
23pub struct Filter {
24    filters: Vec<Box<FilterFn>>,
25}
26
27impl Filter {
28    pub fn any(&self, node: &Node) -> bool {
29        for f in self.filters.iter() {
30            if f(node) {
31                return true;
32            }
33        }
34        false
35    }
36
37    pub fn all(&self, node: &Node) -> bool {
38        for f in self.filters.iter() {
39            if !f(node) {
40                return false;
41            }
42        }
43        true
44    }
45}
46
47#[inline(always)]
48fn get_fake_code<T: TSLanguage>(
49    code: &[u8],
50    path: &Path,
51    pr: Option<Arc<PreprocResults>>,
52) -> Option<Vec<u8>> {
53    if let Some(pr) = pr {
54        match T::get_lang() {
55            LANG::Cpp => {
56                let macros = get_macros(path, &pr.files);
57                c_macro::replace(code, &macros)
58            }
59            _ => None,
60        }
61    } else {
62        None
63    }
64}
65
66impl<T: 'static + TSLanguage + Checker + Getter + Alterator + CodeMetricsT> ParserTrait
67    for Parser<T>
68{
69    type Checker = T;
70    type Getter = T;
71    type Cognitive = T;
72    type Cyclomatic = T;
73    type Halstead = T;
74    type Loc = T;
75    type Nom = T;
76    type Mi = T;
77    type NArgs = T;
78    type Exit = T;
79    type Wmc = T;
80    type Abc = T;
81    type Npm = T;
82    type Npa = T;
83
84    fn new(code: Vec<u8>, path: &Path, pr: Option<Arc<PreprocResults>>) -> Self {
85        let mut parser = TSParser::new();
86        parser.set_language(T::get_language()).unwrap();
87        let fake_code = get_fake_code::<T>(&code, path, pr);
88        /*let tree = if let Some(fake) = fake_code {
89            parser.parse(&fake, None).unwrap()
90        } else {
91            parser.parse(&code, None).unwrap()
92        };*/
93        let code = if let Some(fake) = fake_code {
94            //eprintln!("{}", String::from_utf8(fake.clone()).unwrap());
95            fake
96        } else {
97            code
98        };
99        let tree = parser.parse(&code, None).unwrap();
100
101        Self {
102            code,
103            tree,
104            phantom: PhantomData,
105        }
106    }
107
108    #[inline(always)]
109    fn get_language(&self) -> LANG {
110        T::get_lang()
111    }
112
113    #[inline(always)]
114    fn get_root(&self) -> Node {
115        Node::new(self.tree.root_node())
116    }
117
118    #[inline(always)]
119    fn get_code(&self) -> &[u8] {
120        &self.code
121    }
122
123    fn get_filters(&self, filters: &[String]) -> Filter {
124        let mut res: Vec<Box<FilterFn>> = Vec::new();
125        for f in filters.iter() {
126            let f = f.as_str();
127            match f {
128                "all" => res.push(Box::new(|_: &Node| -> bool { true })),
129                "call" => res.push(Box::new(T::is_call)),
130                "comment" => res.push(Box::new(T::is_comment)),
131                "error" => res.push(Box::new(T::is_error)),
132                "string" => res.push(Box::new(T::is_string)),
133                "function" => res.push(Box::new(T::is_func)),
134                _ => {
135                    if let Ok(n) = f.parse::<u16>() {
136                        res.push(Box::new(move |node: &Node| -> bool {
137                            node.object().kind_id() == n
138                        }));
139                    } else {
140                        let f = f.to_owned();
141                        res.push(Box::new(move |node: &Node| -> bool {
142                            node.object().kind().contains(&f)
143                        }));
144                    }
145                }
146            }
147        }
148        if res.is_empty() {
149            res.push(Box::new(|_: &Node| -> bool { true }))
150        }
151
152        Filter { filters: res }
153    }
154}
155// other => |node: &Node| -> bool { node.kind() == other },