grit_pattern_matcher/
effects.rs

1use crate::context::ExecContext;
2use crate::pattern::ResolvedPattern;
3use crate::{
4    context::QueryContext,
5    pattern::{Pattern, PatternOrResolved, State},
6};
7use grit_util::error::GritResult;
8use grit_util::{error::GritPatternError, EffectKind};
9
10#[derive(Debug, Clone)]
11pub struct Effect<'a, Q: QueryContext> {
12    pub binding: Q::Binding<'a>,
13    pub pattern: Q::ResolvedPattern<'a>,
14    pub kind: EffectKind,
15}
16
17pub fn insert_effect<'a, Q: QueryContext>(
18    left: &PatternOrResolved<'a, '_, Q>,
19    mut replacement: Q::ResolvedPattern<'a>,
20    state: &mut State<'a, Q>,
21    context: &'a Q::ExecContext<'a>,
22) -> GritResult<bool> {
23    match left {
24        PatternOrResolved::Pattern(Pattern::Variable(var)) => {
25            let var = state.trace_var_mut(var);
26            if let Some(base) = state.bindings[var.try_scope().unwrap() as usize]
27                .last_mut()
28                .unwrap()[var.try_index().unwrap() as usize]
29                .value
30                .as_mut()
31            {
32                base.extend(replacement, &mut state.effects, context.language())?;
33                Ok(true)
34            } else {
35                Err(GritPatternError::new(format!(
36                    "Variable {} is not bound",
37                    state.bindings[var.try_scope().unwrap() as usize]
38                        .last()
39                        .unwrap()[var.try_index().unwrap() as usize]
40                        .name
41                )))
42            }
43        }
44        PatternOrResolved::Resolved(resolved) => {
45            let Some(bindings) = resolved.get_bindings() else {
46                return Err(
47                    GritPatternError::new("variable on left hand side of insert side-conditions can only be bound to bindings")
48                );
49            };
50            let effects: GritResult<Vec<_>> = bindings
51                .map(|binding| {
52                    let is_first = !state.effects.iter().any(|e| e.binding == binding);
53                    replacement.normalize_insert(&binding, is_first, context.language())?;
54                    Ok(Effect {
55                        binding,
56                        pattern: replacement.clone(),
57                        kind: EffectKind::Insert,
58                    })
59                })
60                .collect();
61            let effects = effects?;
62            state.effects.extend(effects);
63            Ok(true)
64        }
65        _ => Err(GritPatternError::new(
66            "Invalid left-hand side for insert operation",
67        )),
68    }
69}