grit_pattern_matcher/pattern/
file_pattern.rs

1use super::{
2    patterns::{Matcher, Pattern},
3    resolved_pattern::ResolvedPattern,
4    state::State,
5};
6use crate::{
7    constants::{ABSOLUTE_PATH_INDEX, FILENAME_INDEX, GLOBAL_VARS_SCOPE_INDEX, PROGRAM_INDEX},
8    context::ExecContext,
9};
10use crate::{context::QueryContext, pattern::resolved_pattern::File};
11use grit_util::{error::GritResult, AnalysisLogs};
12
13#[derive(Debug, Clone)]
14pub struct FilePattern<Q: QueryContext> {
15    pub name: Pattern<Q>,
16    pub body: Pattern<Q>,
17}
18
19impl<Q: QueryContext> FilePattern<Q> {
20    pub fn new(name: Pattern<Q>, body: Pattern<Q>) -> Self {
21        Self { name, body }
22    }
23}
24
25impl<Q: QueryContext> Matcher<Q> for FilePattern<Q> {
26    fn execute<'a>(
27        &'a self,
28        resolved_pattern: &Q::ResolvedPattern<'a>,
29        state: &mut State<'a, Q>,
30        context: &'a Q::ExecContext<'a>,
31        logs: &mut AnalysisLogs,
32    ) -> GritResult<bool> {
33        let Some(file) = resolved_pattern.get_file() else {
34            return Ok(false);
35        };
36
37        let name = file.name(&state.files);
38
39        if !self.name.execute(&name, state, context, logs)? {
40            return Ok(false);
41        }
42
43        // If the file isn't loaded yet, we must load it now
44        if !context.load_file(file, state, logs)? {
45            // The file wasn't loaded, so we can't match the body
46            return Ok(false);
47        }
48
49        // Re-execute the name pattern to bind the name variable
50        self.name
51            .execute(&file.name(&state.files), state, context, logs)?;
52
53        // Fill in the variables now - this is a bit of a hack
54        state.bindings[GLOBAL_VARS_SCOPE_INDEX as usize]
55            .last_mut()
56            .unwrap()[PROGRAM_INDEX]
57            .value = Some(file.binding(&state.files));
58        state.bindings[GLOBAL_VARS_SCOPE_INDEX as usize]
59            .last_mut()
60            .unwrap()[FILENAME_INDEX]
61            .value = Some(file.name(&state.files));
62        state.bindings[GLOBAL_VARS_SCOPE_INDEX as usize]
63            .last_mut()
64            .unwrap()[ABSOLUTE_PATH_INDEX]
65            .value = Some(file.name(&state.files));
66        state.bindings[GLOBAL_VARS_SCOPE_INDEX as usize]
67            .last_mut()
68            .unwrap()[ABSOLUTE_PATH_INDEX]
69            .value = Some(file.absolute_path(&state.files, context.language())?);
70
71        if !self
72            .body
73            .execute(&file.binding(&state.files), state, context, logs)?
74        {
75            return Ok(false);
76        }
77
78        Ok(true)
79    }
80}