grit_pattern_matcher/pattern/
rewrite.rs1use super::{
2 dynamic_snippet::DynamicPattern,
3 functions::{Evaluator, FuncEvaluation},
4 patterns::{Matcher, Pattern, PatternName},
5 resolved_pattern::ResolvedPattern,
6 variable_content::VariableContent,
7 State,
8};
9use crate::{context::QueryContext, effects::Effect};
10use core::fmt::Debug;
11use grit_util::{
12 error::{GritPatternError, GritResult},
13 AnalysisLogs, EffectKind,
14};
15use std::borrow::Cow;
16
17#[derive(Debug, Clone)]
18pub struct Rewrite<Q: QueryContext> {
19 pub left: Pattern<Q>,
20 pub right: DynamicPattern<Q>,
21 pub annotation: Option<String>,
22}
23
24impl<Q: QueryContext> Rewrite<Q> {
25 pub fn new(left: Pattern<Q>, right: DynamicPattern<Q>, annotation: Option<String>) -> Self {
26 Self {
27 left,
28 right,
29 annotation,
30 }
31 }
32
33 pub fn new_pattern(
34 left: Pattern<Q>,
35 right: DynamicPattern<Q>,
36 annotation: Option<String>,
37 ) -> Pattern<Q> {
38 Pattern::Rewrite(Box::new(Rewrite {
39 left,
40 right,
41 annotation,
42 }))
43 }
44
45 pub(crate) fn execute_generalized<'a>(
55 &'a self,
56 resolved: Option<&Q::ResolvedPattern<'a>>,
57 state: &mut State<'a, Q>,
58 context: &'a Q::ExecContext<'a>,
59 logs: &mut AnalysisLogs,
60 ) -> GritResult<bool> {
61 let resolved = match resolved {
62 Some(b) => {
63 if !self.left.execute(b, state, context, logs)? {
64 return Ok(false);
65 } else {
66 Cow::Borrowed(b)
67 }
68 }
69 None => {
70 if let Pattern::Variable(v) = &self.left {
71 let var = state.trace_var_mut(v);
72 if let Some(VariableContent {
73 value: Some(content),
74 ..
75 }) = state
76 .bindings
77 .get(var.try_scope().unwrap() as usize)
78 .and_then(|scope| {
79 scope.last().unwrap().get(var.try_index().unwrap() as usize)
80 })
81 .cloned()
82 .map(|b| *b)
83 {
84 Cow::Owned(content)
85 } else {
86 return Err(GritPatternError::new(format!("Variable {:?} not bound", v)));
87 }
88 } else {
89 return Err(GritPatternError::new(
90 "Rewrite side-conditions must have variable on left-hand side",
91 ));
92 }
93 }
94 };
95 let Some(bindings) = resolved.get_bindings() else {
96 return Err(
97 GritPatternError::new(
98
99 "variable on left hand side of rewrite side-conditions can only be bound to bindings"
100 )
101 );
102 };
103 let replacement: Q::ResolvedPattern<'_> =
104 ResolvedPattern::from_dynamic_pattern(&self.right, state, context, logs)?;
105 let effects = bindings.map(|b| Effect {
106 binding: b.clone(),
107 pattern: replacement.clone(),
108 kind: EffectKind::Rewrite,
109 });
110 state.effects.extend(effects);
111 Ok(true)
112 }
113}
114
115impl<Q: QueryContext> PatternName for Rewrite<Q> {
116 fn name(&self) -> &'static str {
117 "REWRITE"
118 }
119}
120
121impl<Q: QueryContext> Matcher<Q> for Rewrite<Q> {
122 fn execute<'a>(
123 &'a self,
124 binding: &Q::ResolvedPattern<'a>,
125 state: &mut State<'a, Q>,
126 context: &'a Q::ExecContext<'a>,
127 logs: &mut AnalysisLogs,
128 ) -> GritResult<bool> {
129 self.execute_generalized(Some(binding), state, context, logs)
130 }
131}
132
133impl<Q: QueryContext> Evaluator<Q> for Rewrite<Q> {
134 fn execute_func<'a>(
135 &'a self,
136 state: &mut State<'a, Q>,
137 context: &'a Q::ExecContext<'a>,
138 logs: &mut AnalysisLogs,
139 ) -> GritResult<FuncEvaluation<Q>> {
140 let predicator = self.execute_generalized(None, state, context, logs)?;
141 Ok(FuncEvaluation {
142 predicator,
143 ret_val: None,
144 })
145 }
146}