rust_code_analysis/
parser.rs1use 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, ¯os)
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 code = if let Some(fake) = fake_code {
94 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