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, ¯os)
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}