Skip to main content

codelore_rca/
parser.rs

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