grit_pattern_matcher/pattern/
match.rs

1use super::{
2    container::Container,
3    functions::{Evaluator, FuncEvaluation},
4    patterns::{Matcher, Pattern, PatternName},
5    resolved_pattern::ResolvedPattern,
6    State,
7};
8use crate::pattern::functions::GritCall;
9use crate::{
10    context::{ExecContext, QueryContext},
11    errors::debug,
12};
13use grit_util::{error::GritResult, AnalysisLogs};
14
15#[derive(Debug, Clone)]
16pub struct Match<Q: QueryContext> {
17    pub val: Container<Q>,
18    pub pattern: Option<Pattern<Q>>,
19}
20
21impl<Q: QueryContext> Match<Q> {
22    pub fn new(val: Container<Q>, pattern: Option<Pattern<Q>>) -> Self {
23        Self { val, pattern }
24    }
25}
26
27impl<Q: QueryContext> PatternName for Match<Q> {
28    fn name(&self) -> &'static str {
29        "MATCH"
30    }
31}
32
33impl<Q: QueryContext> Evaluator<Q> for Match<Q> {
34    fn execute_func<'a>(
35        &'a self,
36        state: &mut State<'a, Q>,
37        context: &'a Q::ExecContext<'a>,
38        logs: &mut AnalysisLogs,
39    ) -> GritResult<FuncEvaluation<Q>> {
40        match &self.val {
41            Container::Variable(var) => {
42                let var = state.trace_var_mut(var);
43                let var_content = &state.bindings[var.try_scope().unwrap() as usize]
44                    .last()
45                    .unwrap()[var.try_index().unwrap() as usize];
46                let predicator = if let Some(pattern) = &self.pattern {
47                    if let Some(important_binding) = &var_content.value {
48                        pattern.execute(&important_binding.clone(), state, context, logs)?
49                    } else if let Some(var_pattern) = var_content.pattern {
50                        let resolved_pattern =
51                            ResolvedPattern::from_pattern(var_pattern, state, context, logs)?;
52                        pattern.execute(&resolved_pattern, state, context, logs)?
53                    } else if let Some(Pattern::BooleanConstant(b)) = &self.pattern {
54                        if !b.value {
55                            true
56                        } else {
57                            let resolved_pattern = ResolvedPattern::undefined();
58                            let res = pattern.execute(&resolved_pattern, state, context, logs)?;
59                            if !res {
60                                let message = format!(
61                                    "Attempted to match against undefined variable {}",
62                                    state.get_name(&var)
63                                );
64                                debug(logs, state, context.language(), message.as_str())?;
65                            }
66                            res
67                        }
68                    } else {
69                        let resolved_pattern = ResolvedPattern::undefined();
70                        let res = pattern.execute(&resolved_pattern, state, context, logs)?;
71                        if !res {
72                            let message = format!(
73                                "Attempted to match against undefined variable {}",
74                                state.get_name(&var)
75                            );
76                            debug(logs, state, context.language(), message.as_str())?;
77                        }
78                        res
79                    }
80                } else {
81                    var_content.value.is_none() && var_content.pattern.is_none()
82                        || var_content
83                            .value
84                            .as_ref()
85                            .is_some_and(|v| v.matches_undefined())
86                };
87                Ok(FuncEvaluation {
88                    predicator,
89                    ret_val: None,
90                })
91            }
92            Container::Accessor(accessor) => {
93                let resolved_accessor =
94                    ResolvedPattern::from_accessor(accessor, state, context, logs)?;
95                let predicator = if let Some(pattern) = &self.pattern {
96                    pattern.execute(&resolved_accessor, state, context, logs)?
97                } else {
98                    resolved_accessor.matches_undefined()
99                };
100                Ok(FuncEvaluation {
101                    predicator,
102                    ret_val: None,
103                })
104            }
105            Container::ListIndex(index) => {
106                let resolved_accessor =
107                    ResolvedPattern::from_list_index(index, state, context, logs)?;
108                let predicator = if let Some(pattern) = &self.pattern {
109                    pattern.execute(&resolved_accessor, state, context, logs)?
110                } else {
111                    resolved_accessor.matches_undefined()
112                };
113                Ok(FuncEvaluation {
114                    predicator,
115                    ret_val: None,
116                })
117            }
118            Container::FunctionCall(f) => {
119                let resolved_accessor = f.call(state, context, logs)?;
120                Ok(FuncEvaluation {
121                    predicator: if let Some(pattern) = &self.pattern {
122                        pattern.execute(&resolved_accessor, state, context, logs)?
123                    } else {
124                        resolved_accessor.matches_undefined()
125                    },
126                    ret_val: None,
127                })
128            }
129        }
130    }
131}