grit_pattern_matcher/pattern/
patterns.rs

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    // it is important that any implementors of Pattern
62    // do not compute-expensive things in execute
63    // it should be stored somewhere in the struct of the implementor
64    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    // for the future:
73    // we could speed up computation by filtering on the sort of pattern
74    // here, &SortFormula is a propositional-logic formula over sorts
75    // fn sort(&self) -> SortFormula;
76}
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    // differentiated from top for debugging purposes.
111    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    // todo this should return a cow, but currently can't figure out lifetimes
142    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    /// Return the different patterns which could *all* possibly match the code snippet.
319    fn patterns(&self) -> impl Iterator<Item = &Pattern<Q>>;
320
321    fn dynamic_snippet(&self) -> Option<&DynamicPattern<Q>>;
322}