grit_pattern_matcher/pattern/
pattern_definition.rs

1use super::{
2    patterns::{Matcher, Pattern},
3    variable::Variable,
4    State,
5};
6use crate::context::QueryContext;
7use grit_util::{
8    error::{GritPatternError, GritResult},
9    AnalysisLogs,
10};
11use rand::Rng as _;
12
13#[derive(Clone, Debug)]
14pub enum PatternDefinitionInternal {
15    Static { scope: usize },
16    Dynamic,
17}
18
19#[derive(Clone, Debug)]
20pub struct PatternDefinition<Q: QueryContext> {
21    pub name: String,
22    pattern: Pattern<Q>,
23    params: Vec<(String, Variable)>,
24    internal: PatternDefinitionInternal,
25}
26
27impl<Q: QueryContext> PatternDefinition<Q> {
28    pub fn new(
29        name: String,
30        scope: usize,
31        params: Vec<(String, Variable)>,
32        pattern: Pattern<Q>,
33    ) -> Self {
34        Self {
35            name,
36            pattern,
37            params,
38            internal: PatternDefinitionInternal::Static { scope },
39        }
40    }
41
42    /// Create an unnamed ephemeral pattern
43    /// This is primarily useful for the bubble pattern, where we want to create a new scope
44    pub fn new_ephemeral(params: Vec<(String, Variable)>, pattern: Pattern<Q>) -> Self {
45        let random_name = format!("<bubble:{}>", rand::thread_rng().gen::<u32>());
46
47        Self {
48            name: random_name,
49            pattern,
50            params,
51            internal: PatternDefinitionInternal::Dynamic,
52        }
53    }
54
55    pub fn try_scope(&self) -> GritResult<usize> {
56        match &self.internal {
57            PatternDefinitionInternal::Static { scope } => Ok(*scope),
58            PatternDefinitionInternal::Dynamic {} => Err(GritPatternError::new(
59                "Dynamic pattern definitions do not have a scope",
60            )),
61        }
62    }
63
64    pub fn replace_pattern(&mut self, new_pattern: Pattern<Q>) {
65        self.pattern = new_pattern;
66    }
67
68    fn get_scope(&self, state: &mut State<'_, Q>) -> usize {
69        match &self.internal {
70            PatternDefinitionInternal::Static { scope } => *scope,
71            PatternDefinitionInternal::Dynamic { .. } => {
72                state.register_pattern_definition(&self.name)
73            }
74        }
75    }
76
77    pub(crate) fn call<'a>(
78        &'a self,
79        state: &mut State<'a, Q>,
80        binding: &Q::ResolvedPattern<'a>,
81        context: &'a Q::ExecContext<'a>,
82        logs: &mut AnalysisLogs,
83        args: &'a [Option<Pattern<Q>>],
84    ) -> GritResult<bool> {
85        let scope = self.get_scope(state);
86        let tracker = state.enter_scope(scope, args);
87
88        let res = self.pattern.execute(binding, state, context, logs);
89        state.exit_scope(tracker);
90
91        let fn_state = state.bindings[scope].pop().unwrap();
92        let cur_fn_state = state.bindings[scope].last_mut().unwrap();
93        for (cur, last) in cur_fn_state.iter_mut().zip(fn_state) {
94            cur.value_history.extend(last.value_history)
95        }
96        res
97    }
98
99    pub fn params(&self) -> &Vec<(String, Variable)> {
100        &self.params
101    }
102
103    pub fn pattern(&self) -> &Pattern<Q> {
104        &self.pattern
105    }
106}