grit_pattern_matcher/
context.rs

1use crate::{
2    binding::Binding,
3    file_owners::FileOwners,
4    pattern::{
5        AstLeafNodePattern, AstNodePattern, CallBuiltIn, CallbackPattern, CodeSnippet, File,
6        GritFunctionDefinition, Pattern, PatternDefinition, PredicateDefinition, ResolvedPattern,
7        State,
8    },
9};
10use grit_util::{error::GritResult, AnalysisLogs, Ast, AstNode, Language};
11
12/// Contains various kinds of context about the query being executed.
13pub trait QueryContext: Clone + std::fmt::Debug + Sized + 'static {
14    type Node<'a>: AstNode + Clone;
15    type NodePattern: AstNodePattern<Self>;
16    type LeafNodePattern: AstLeafNodePattern<Self>;
17    type ExecContext<'a>: ExecContext<'a, Self>;
18    type Binding<'a>: Binding<'a, Self>;
19    type CodeSnippet: CodeSnippet<Self>;
20    type ResolvedPattern<'a>: ResolvedPattern<'a, Self>;
21    type Language<'a>: Language<Node<'a> = Self::Node<'a>>;
22    type File<'a>: File<'a, Self>;
23    type Tree<'a>: Ast<Node<'a> = Self::Node<'a>> + Clone;
24}
25
26/// Contains context necessary for query execution.
27pub trait ExecContext<'a, Q: QueryContext> {
28    fn pattern_definitions(&self) -> &[PatternDefinition<Q>];
29
30    fn predicate_definitions(&self) -> &[PredicateDefinition<Q>];
31
32    fn function_definitions(&self) -> &[GritFunctionDefinition<Q>];
33
34    fn ignore_limit_pattern(&self) -> bool;
35
36    fn call_built_in(
37        &self,
38        call: &'a CallBuiltIn<Q>,
39        context: &'a Self,
40        state: &mut State<'a, Q>,
41        logs: &mut AnalysisLogs,
42    ) -> GritResult<Q::ResolvedPattern<'a>>;
43
44    fn call_callback<'b>(
45        &self,
46        call: &'a CallbackPattern,
47        context: &'a Self,
48        binding: &'b Q::ResolvedPattern<'a>,
49        state: &mut State<'a, Q>,
50        logs: &mut AnalysisLogs,
51    ) -> GritResult<bool>;
52
53    /// Call this when "entering" a file to lazily load it.
54    /// This MUST be implemented correctly, or the query engine will not work.
55    ///
56    // TODO: ideally this should be async, but that requires engine-wide async support.
57    fn load_file(
58        &self,
59        file: &Q::File<'a>,
60        state: &mut State<'a, Q>,
61        logs: &mut AnalysisLogs,
62    ) -> GritResult<bool>;
63
64    // FIXME: Don't depend on Grit's file handling in Context.
65    fn files(&self) -> &FileOwners<Q::Tree<'a>>;
66
67    fn language(&self) -> &Q::Language<'a>;
68
69    fn exec_step(
70        &'a self,
71        step: &'a Pattern<Q>,
72        binding: &Q::ResolvedPattern<'a>,
73        state: &mut State<'a, Q>,
74        logs: &mut AnalysisLogs,
75    ) -> GritResult<bool>;
76
77    fn name(&self) -> Option<&str>;
78}
79
80/// Static information used for a pattern
81/// This is useful for static analysis of patterns without running the query engine.
82#[derive(Debug)]
83pub struct StaticDefinitions<'a, Q: QueryContext> {
84    pattern_definitions: &'a [PatternDefinition<Q>],
85    predicate_definitions: &'a [PredicateDefinition<Q>],
86    function_definitions: &'a [GritFunctionDefinition<Q>],
87    /// Pattern indexes we should skip during analysis (before_each_file / after_each_file)
88    pub skippable_indexes: Vec<usize>,
89}
90
91impl<'a, Q: QueryContext> StaticDefinitions<'a, Q> {
92    pub fn new(
93        pattern_definitions: &'a [PatternDefinition<Q>],
94        predicate_definitions: &'a [PredicateDefinition<Q>],
95        function_definitions: &'a [GritFunctionDefinition<Q>],
96    ) -> Self {
97        StaticDefinitions {
98            pattern_definitions,
99            predicate_definitions,
100            function_definitions,
101            skippable_indexes: vec![],
102        }
103    }
104
105    pub fn get_pattern(&self, index: usize) -> Option<&PatternDefinition<Q>> {
106        if self.skippable_indexes.contains(&index) {
107            return None;
108        }
109        self.pattern_definitions.get(index)
110    }
111
112    pub fn get_predicate(&self, index: usize) -> Option<&PredicateDefinition<Q>> {
113        self.predicate_definitions.get(index)
114    }
115
116    pub fn get_function(&self, index: usize) -> Option<&GritFunctionDefinition<Q>> {
117        self.function_definitions.get(index)
118    }
119}
120
121impl<'a, Q: QueryContext> Default for StaticDefinitions<'a, Q> {
122    fn default() -> Self {
123        Self {
124            pattern_definitions: &[],
125            predicate_definitions: &[],
126            function_definitions: &[],
127            skippable_indexes: vec![],
128        }
129    }
130}