grit_pattern_matcher/
effects.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
use crate::context::ExecContext;
use crate::pattern::ResolvedPattern;
use crate::{
    context::QueryContext,
    pattern::{Pattern, PatternOrResolved, State},
};
use grit_util::error::GritResult;
use grit_util::{error::GritPatternError, EffectKind};

#[derive(Debug, Clone)]
pub struct Effect<'a, Q: QueryContext> {
    pub binding: Q::Binding<'a>,
    pub pattern: Q::ResolvedPattern<'a>,
    pub kind: EffectKind,
}

pub fn insert_effect<'a, Q: QueryContext>(
    left: &PatternOrResolved<'a, '_, Q>,
    mut replacement: Q::ResolvedPattern<'a>,
    state: &mut State<'a, Q>,
    context: &'a Q::ExecContext<'a>,
) -> GritResult<bool> {
    match left {
        PatternOrResolved::Pattern(Pattern::Variable(var)) => {
            let var = state.trace_var_mut(var);
            if let Some(base) = state.bindings[var.try_scope().unwrap() as usize]
                .last_mut()
                .unwrap()[var.try_index().unwrap() as usize]
                .value
                .as_mut()
            {
                base.extend(replacement, &mut state.effects, context.language())?;
                Ok(true)
            } else {
                Err(GritPatternError::new(format!(
                    "Variable {} is not bound",
                    state.bindings[var.try_scope().unwrap() as usize]
                        .last()
                        .unwrap()[var.try_index().unwrap() as usize]
                        .name
                )))
            }
        }
        PatternOrResolved::Resolved(resolved) => {
            let Some(bindings) = resolved.get_bindings() else {
                return Err(
                    GritPatternError::new("variable on left hand side of insert side-conditions can only be bound to bindings")
                );
            };
            let effects: GritResult<Vec<_>> = bindings
                .map(|binding| {
                    let is_first = !state.effects.iter().any(|e| e.binding == binding);
                    replacement.normalize_insert(&binding, is_first, context.language())?;
                    Ok(Effect {
                        binding,
                        pattern: replacement.clone(),
                        kind: EffectKind::Insert,
                    })
                })
                .collect();
            let effects = effects?;
            state.effects.extend(effects);
            Ok(true)
        }
        _ => Err(GritPatternError::new(
            "Invalid left-hand side for insert operation",
        )),
    }
}