1use super::{
2 accessor::Accessor,
3 accumulate::Accumulate,
4 add::Add,
5 after::After,
6 and::And,
7 any::Any,
8 assignment::Assignment,
9 before::Before,
10 boolean_constant::BooleanConstant,
11 bubble::Bubble,
12 call::Call,
13 call_built_in::CallBuiltIn,
14 contains::Contains,
15 divide::Divide,
16 dynamic_snippet::DynamicPattern,
17 every::Every,
18 file_pattern::FilePattern,
19 files::Files,
20 float_constant::FloatConstant,
21 functions::{CallForeignFunction, CallFunction},
22 includes::Includes,
23 int_constant::IntConstant,
24 like::Like,
25 limit::Limit,
26 list::List,
27 list_index::ListIndex,
28 map::GritMap,
29 maybe::Maybe,
30 modulo::Modulo,
31 multiply::Multiply,
32 not::Not,
33 or::Or,
34 r#if::If,
35 r#where::Where,
36 range::Range as PRange,
37 regex::RegexPattern,
38 resolved_pattern::ResolvedPattern,
39 rewrite::Rewrite,
40 sequential::Sequential,
41 some::Some,
42 string_constant::StringConstant,
43 subtract::Subtract,
44 undefined::Undefined,
45 variable::Variable,
46 within::Within,
47 CallbackPattern, State,
48};
49use crate::{
50 constants::{FILENAME_INDEX, GLOBAL_VARS_SCOPE_INDEX},
51 context::{ExecContext, QueryContext},
52 pattern::resolved_pattern::File,
53};
54use core::fmt::Debug;
55use grit_util::{
56 error::{GritPatternError, GritResult},
57 AnalysisLogs,
58};
59
60pub trait Matcher<Q: QueryContext>: Debug {
61 fn execute<'a>(
65 &'a self,
66 binding: &Q::ResolvedPattern<'a>,
67 state: &mut State<'a, Q>,
68 context: &'a Q::ExecContext<'a>,
69 logs: &mut AnalysisLogs,
70 ) -> GritResult<bool>;
71
72 }
77
78pub trait PatternName {
79 fn name(&self) -> &'static str;
80}
81
82#[derive(Debug, Clone)]
83pub enum Pattern<Q: QueryContext> {
84 AstNode(Box<Q::NodePattern>),
85 List(Box<List<Q>>),
86 ListIndex(Box<ListIndex<Q>>),
87 Map(Box<GritMap<Q>>),
88 Accessor(Box<Accessor<Q>>),
89 Call(Box<Call<Q>>),
90 Regex(Box<RegexPattern<Q>>),
91 File(Box<FilePattern<Q>>),
92 Files(Box<Files<Q>>),
93 Bubble(Box<Bubble<Q>>),
94 Limit(Box<Limit<Q>>),
95 CallBuiltIn(Box<CallBuiltIn<Q>>),
96 CallFunction(Box<CallFunction<Q>>),
97 CallForeignFunction(Box<CallForeignFunction<Q>>),
98 CallbackPattern(Box<CallbackPattern>),
99 Assignment(Box<Assignment<Q>>),
100 Accumulate(Box<Accumulate<Q>>),
101 And(Box<And<Q>>),
102 Or(Box<Or<Q>>),
103 Maybe(Box<Maybe<Q>>),
104 Any(Box<Any<Q>>),
105 Not(Box<Not<Q>>),
106 If(Box<If<Q>>),
107 Undefined,
108 Top,
109 Bottom,
110 Underscore,
112 StringConstant(StringConstant),
113 AstLeafNode(Q::LeafNodePattern),
114 IntConstant(IntConstant),
115 FloatConstant(FloatConstant),
116 BooleanConstant(BooleanConstant),
117 Dynamic(DynamicPattern<Q>),
118 CodeSnippet(Q::CodeSnippet),
119 Variable(Variable),
120 Rewrite(Box<Rewrite<Q>>),
121 Range(PRange),
122 Contains(Box<Contains<Q>>),
123 Includes(Box<Includes<Q>>),
124 Within(Box<Within<Q>>),
125 After(Box<After<Q>>),
126 Before(Box<Before<Q>>),
127 Where(Box<Where<Q>>),
128 Some(Box<Some<Q>>),
129 Every(Box<Every<Q>>),
130 Add(Box<Add<Q>>),
131 Subtract(Box<Subtract<Q>>),
132 Multiply(Box<Multiply<Q>>),
133 Divide(Box<Divide<Q>>),
134 Modulo(Box<Modulo<Q>>),
135 Dots,
136 Sequential(Sequential<Q>),
137 Like(Box<Like<Q>>),
138}
139
140impl<Q: QueryContext> Pattern<Q> {
141 pub fn text<'a>(
143 &'a self,
144 state: &mut State<'a, Q>,
145 context: &'a Q::ExecContext<'a>,
146 logs: &mut AnalysisLogs,
147 ) -> GritResult<String> {
148 Ok(
149 Q::ResolvedPattern::from_pattern(self, state, context, logs)?
150 .text(&state.files, context.language())?
151 .to_string(),
152 )
153 }
154
155 pub(crate) fn float<'a>(
156 &'a self,
157 state: &mut State<'a, Q>,
158 context: &'a Q::ExecContext<'a>,
159 logs: &mut AnalysisLogs,
160 ) -> GritResult<f64> {
161 Q::ResolvedPattern::from_pattern(self, state, context, logs)?
162 .float(&state.files, context.language())
163 }
164}
165
166impl<Q: QueryContext> PatternName for Pattern<Q> {
167 fn name(&self) -> &'static str {
168 match self {
169 Pattern::AstNode(ast_node) => ast_node.name(),
170 Pattern::Some(some) => some.name(),
171 Pattern::Every(every) => every.name(),
172 Pattern::List(nodes) => nodes.name(),
173 Pattern::ListIndex(index) => index.name(),
174 Pattern::Map(map) => map.name(),
175 Pattern::Accessor(accessor) => accessor.name(),
176 Pattern::Call(pattern_call) => pattern_call.name(),
177 Pattern::Regex(regex) => regex.name(),
178 Pattern::File(_pattern_call) => "FILE_PATTERN",
179 Pattern::Files(_) => "MULTIFILE",
180 Pattern::Bubble(pattern_call) => pattern_call.name(),
181 Pattern::Limit(limit) => limit.name(),
182 Pattern::CallBuiltIn(built_in) => built_in.name(),
183 Pattern::CallFunction(call_function) => call_function.name(),
184 Pattern::CallForeignFunction(call_function) => call_function.name(),
185 Pattern::CallbackPattern(callback) => callback.name(),
186 Pattern::Assignment(assignment) => assignment.name(),
187 Pattern::Accumulate(accumulate) => accumulate.name(),
188 Pattern::StringConstant(string_constant) => string_constant.name(),
189 Pattern::AstLeafNode(leaf_node) => leaf_node.name(),
190 Pattern::IntConstant(int_constant) => int_constant.name(),
191 Pattern::FloatConstant(double_constant) => double_constant.name(),
192 Pattern::BooleanConstant(boolean_constant) => boolean_constant.name(),
193 Pattern::Variable(variable) => variable.name(),
194 Pattern::Add(add) => add.name(),
195 Pattern::Subtract(subtract) => subtract.name(),
196 Pattern::Multiply(multiply) => multiply.name(),
197 Pattern::Divide(divide) => divide.name(),
198 Pattern::Modulo(modulo) => modulo.name(),
199 Pattern::And(and) => and.name(),
200 Pattern::Or(or) => or.name(),
201 Pattern::Maybe(maybe) => maybe.name(),
202 Pattern::Any(any) => any.name(),
203 Pattern::CodeSnippet(code_snippet) => code_snippet.name(),
204 Pattern::Rewrite(rewrite) => rewrite.name(),
205 Pattern::Range(range) => range.name(),
206 Pattern::Contains(contains) => contains.name(),
207 Pattern::Includes(includes) => includes.name(),
208 Pattern::Within(within) => within.name(),
209 Pattern::After(after) => after.name(),
210 Pattern::Before(before) => before.name(),
211 Pattern::Where(where_) => where_.name(),
212 Pattern::Undefined => "UNDEFINED",
213 Pattern::Top => "TOP",
214 Pattern::Underscore => "UNDERSCORE",
215 Pattern::Bottom => "BOTTOM",
216 Pattern::Not(not) => not.name(),
217 Pattern::If(if_) => if_.name(),
218 Pattern::Dots => "DOTS",
219 Pattern::Dynamic(dynamic_pattern) => dynamic_pattern.name(),
220 Pattern::Sequential(sequential) => sequential.name(),
221 Pattern::Like(like) => like.name(),
222 }
223 }
224}
225
226impl<Q: QueryContext> Matcher<Q> for Pattern<Q> {
227 fn execute<'a>(
228 &'a self,
229 binding: &Q::ResolvedPattern<'a>,
230 state: &mut State<'a, Q>,
231 context: &'a Q::ExecContext<'a>,
232 logs: &mut AnalysisLogs,
233 ) -> GritResult<bool> {
234 if let Some(file) = binding.get_file() {
235 state.bindings[GLOBAL_VARS_SCOPE_INDEX as usize]
236 .last_mut()
237 .unwrap()[FILENAME_INDEX]
238 .value = Some(file.name(&state.files));
239 }
240
241 match self {
242 Pattern::AstNode(ast_node) => ast_node.execute(binding, state, context, logs),
243 Pattern::Some(some) => some.execute(binding, state, context, logs),
244 Pattern::Every(every) => every.execute(binding, state, context, logs),
245 Pattern::List(patterns) => patterns.execute(binding, state, context, logs),
246 Pattern::ListIndex(index) => index.execute(binding, state, context, logs),
247 Pattern::Map(map) => map.execute(binding, state, context, logs),
248 Pattern::Accessor(accessor) => accessor.execute(binding, state, context, logs),
249 Pattern::Files(files) => files.execute(binding, state, context, logs),
250 Pattern::Call(pattern_call) => pattern_call.execute(binding, state, context, logs),
251 Pattern::Regex(regex) => regex.execute(binding, state, context, logs),
252 Pattern::File(file_pattern) => file_pattern.execute(binding, state, context, logs),
253 Pattern::Bubble(pattern_call) => pattern_call.execute(binding, state, context, logs),
254 Pattern::Limit(limit) => limit.execute(binding, state, context, logs),
255 Pattern::CallBuiltIn(_) => Err(GritPatternError::new_matcher(
256 "CallBuiltIn cannot be executed at the moment",
257 )),
258 Pattern::CallFunction(_) => Err(GritPatternError::new_matcher(
259 "CallFunction cannot be executed at the moment",
260 )),
261 Pattern::CallForeignFunction(_) => Err(GritPatternError::new_matcher(
262 "CallForeignFunction cannot be executed at the moment",
263 )),
264 Pattern::CallbackPattern(callback) => callback.execute(binding, state, context, logs),
265 Pattern::Assignment(assignment) => assignment.execute(binding, state, context, logs),
266 Pattern::Accumulate(accumulate) => accumulate.execute(binding, state, context, logs),
267 Pattern::StringConstant(string_constant) => {
268 string_constant.execute(binding, state, context, logs)
269 }
270 Pattern::AstLeafNode(leaf_node) => leaf_node.execute(binding, state, context, logs),
271 Pattern::IntConstant(int_constant) => {
272 int_constant.execute(binding, state, context, logs)
273 }
274 Pattern::FloatConstant(double_constant) => {
275 double_constant.execute(binding, state, context, logs)
276 }
277 Pattern::BooleanConstant(boolean_constant) => {
278 boolean_constant.execute(binding, state, context, logs)
279 }
280 Pattern::Variable(variable) => variable.execute(binding, state, context, logs),
281 Pattern::Add(add) => add.execute(binding, state, context, logs),
282 Pattern::Subtract(subtract) => subtract.execute(binding, state, context, logs),
283 Pattern::Multiply(multiply) => multiply.execute(binding, state, context, logs),
284 Pattern::Divide(divide) => divide.execute(binding, state, context, logs),
285 Pattern::Modulo(modulo) => modulo.execute(binding, state, context, logs),
286 Pattern::And(and) => and.execute(binding, state, context, logs),
287 Pattern::Or(or) => or.execute(binding, state, context, logs),
288 Pattern::Maybe(maybe) => maybe.execute(binding, state, context, logs),
289 Pattern::Any(any) => any.execute(binding, state, context, logs),
290 Pattern::CodeSnippet(code_snippet) => {
291 code_snippet.execute(binding, state, context, logs)
292 }
293 Pattern::Rewrite(rewrite) => rewrite.execute(binding, state, context, logs),
294 Pattern::Range(range) => range.execute(binding, state, context, logs),
295 Pattern::Contains(contains) => contains.execute(binding, state, context, logs),
296 Pattern::Includes(includes) => includes.execute(binding, state, context, logs),
297 Pattern::Within(within) => within.execute(binding, state, context, logs),
298 Pattern::After(after) => after.execute(binding, state, context, logs),
299 Pattern::Before(before) => before.execute(binding, state, context, logs),
300 Pattern::Where(where_) => where_.execute(binding, state, context, logs),
301 Pattern::Undefined => Undefined::execute(binding, state, context, logs),
302 Pattern::Top => Ok(true),
303 Pattern::Underscore => Ok(true),
304 Pattern::Bottom => Ok(false),
305 Pattern::Not(not) => not.execute(binding, state, context, logs),
306 Pattern::If(if_) => if_.execute(binding, state, context, logs),
307 Pattern::Dots => Err(GritPatternError::new(
308 "Dots should only be directly within a list pattern.",
309 )),
310 Pattern::Dynamic(pattern) => pattern.execute(binding, state, context, logs),
311 Pattern::Sequential(sequential) => sequential.execute(binding, state, context, logs),
312 Pattern::Like(like) => like.execute(binding, state, context, logs),
313 }
314 }
315}
316
317pub trait CodeSnippet<Q: QueryContext + 'static>: Clone + Debug + Matcher<Q> + PatternName {
318 fn patterns(&self) -> impl Iterator<Item = &Pattern<Q>>;
320
321 fn dynamic_snippet(&self) -> Option<&DynamicPattern<Q>>;
322}