Skip to main content

rust_code_analysis_code_split/
parser.rs

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