grit_pattern_matcher/pattern/
accumulate.rs1use super::{
2 dynamic_snippet::DynamicPattern,
3 functions::{Evaluator, FuncEvaluation},
4 patterns::{Matcher, Pattern, PatternName},
5 resolved_pattern::ResolvedPattern,
6 PatternOrResolved, State,
7};
8use crate::{
9 context::{ExecContext, QueryContext},
10 effects::insert_effect,
11};
12use grit_util::{
13 error::{GritPatternError, GritResult},
14 AnalysisLogs,
15};
16
17#[derive(Debug, Clone)]
18pub struct Accumulate<Q: QueryContext> {
19 pub(crate) left: Pattern<Q>,
20 pub(crate) right: Pattern<Q>,
21 dynamic_right: Option<DynamicPattern<Q>>,
22}
23
24impl<Q: QueryContext> Accumulate<Q> {
25 pub fn new(
26 left: Pattern<Q>,
27 right: Pattern<Q>,
28 dynamic_right: Option<DynamicPattern<Q>>,
29 ) -> Self {
30 Self {
31 left,
32 right,
33 dynamic_right,
34 }
35 }
36}
37
38impl<Q: QueryContext> PatternName for Accumulate<Q> {
39 fn name(&self) -> &'static str {
40 "ACCUMULATE"
41 }
42}
43
44impl<Q: QueryContext> Matcher<Q> for Accumulate<Q> {
45 fn execute<'a>(
46 &'a self,
47 context_node: &Q::ResolvedPattern<'a>,
48 state: &mut State<'a, Q>,
49 context: &'a Q::ExecContext<'a>,
50 logs: &mut AnalysisLogs,
51 ) -> GritResult<bool> {
52 if let Pattern::Variable(_) = &self.left {
53 let left = PatternOrResolved::Pattern(&self.left);
54 let right = ResolvedPattern::from_pattern(&self.right, state, context, logs)?;
55 insert_effect(&left, right, state, context)
56 } else {
57 if !self.left.execute(context_node, state, context, logs)? {
58 return Ok(false);
59 };
60 let resolved = context_node;
61 let left = PatternOrResolved::Resolved(resolved);
62
63 let right = if let Some(dynamic_right) = &self.dynamic_right {
64 ResolvedPattern::from_dynamic_pattern(dynamic_right, state, context, logs)?
65 } else {
66 ResolvedPattern::from_pattern(&self.right, state, context, logs)?
67 };
68
69 insert_effect(&left, right, state, context)
70 }
71 }
72}
73
74impl<Q: QueryContext> Evaluator<Q> for Accumulate<Q> {
75 fn execute_func<'a>(
76 &'a self,
77 state: &mut State<'a, Q>,
78 context: &'a Q::ExecContext<'a>,
79 logs: &mut AnalysisLogs,
80 ) -> GritResult<FuncEvaluation<Q>> {
81 if let Pattern::Variable(var) = &self.left {
82 let var = state.trace_var_mut(var);
83 let append = ResolvedPattern::from_pattern(&self.right, state, context, logs)?;
84 let scope = var.get_scope(state)?;
85 let index = var.get_index(state)?;
86 if let Some(base) = state.bindings[scope as usize].last_mut().unwrap()[index as usize]
87 .value
88 .as_mut()
89 {
90 base.extend(append, &mut state.effects, context.language())?;
91 Ok(FuncEvaluation {
92 predicator: true,
93 ret_val: None,
94 })
95 } else {
96 Err(GritPatternError::new(format!(
97 "Variable {} is not bound",
98 state.bindings[var.try_scope().unwrap() as usize]
99 .last()
100 .unwrap()[var.try_index().unwrap() as usize]
101 .name
102 )))
103 }
104 } else {
105 Err(GritPatternError::new(
106 "Insert side-conditions must have variable on left-hand side",
107 ))
108 }
109 }
110}