grit_pattern_matcher/pattern/
match.rs1use 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}