1use crate::cost;
8use crate::lang::Lang;
9use crate::walk::Walk;
10
11#[derive(Debug)]
13pub enum Edit<L: Lang> {
14 Replace { target: L::Id, with: L::Id },
16 Delete { node: L::Id },
18 Splice {
20 node: L::Id,
21 index: usize,
22 remove: usize,
23 insert: Vec<L::Id>,
24 },
25 Multi(Vec<Edit<L>>),
29}
30
31impl<L: Lang> Edit<L> {
32 pub fn cost_reduction(&self, lang: &mut L) -> u64 {
34 match self {
35 Edit::Replace { target, with } => {
36 let a = cost::subtree_cost(lang, *target);
37 let b = cost::subtree_cost(lang, *with);
38 a.saturating_sub(b)
39 }
40 Edit::Delete { node } => cost::subtree_cost(lang, *node),
41 Edit::Splice {
42 node,
43 index,
44 remove,
45 insert,
46 } => {
47 let children = lang.children(*node);
48 let mut removed = 0u64;
49 for &c in &children[*index..(*index + remove).min(children.len())] {
50 removed += cost::subtree_cost(lang, c);
51 }
52 let mut added = 0u64;
53 for &n in insert.iter() {
54 added += cost::subtree_cost(lang, n);
55 }
56 removed.saturating_sub(added)
57 }
58 Edit::Multi(edits) => edits.iter().map(|e| e.cost_reduction(lang)).sum(),
59 }
60 }
61}
62
63pub struct RewriteCtx<'a, L: Lang> {
65 pub lang: &'a mut L,
66 pub(crate) walk: &'a Walk<L>,
67}
68
69impl<'a, L: Lang> RewriteCtx<'a, L> {
70 pub fn parent(&self, id: L::Id) -> Option<L::Id> {
71 self.walk.parent(id)
72 }
73 pub fn index(&self, id: L::Id) -> Option<usize> {
74 self.walk.index(id)
75 }
76 pub fn root(&self) -> L::Id {
77 self.walk.root
78 }
79}
80
81pub trait Rule<L: Lang> {
83 fn name(&self) -> &'static str;
84
85 fn kinds(&self) -> &'static [crate::kind::NodeKind] {
90 &[]
91 }
92
93 fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>>;
96
97 fn structural(&self) -> bool {
101 false
102 }
103}
104
105pub(crate) fn apply_edit<L: Lang>(
107 lang: &mut L,
108 walk: &Walk<L>,
109 edit: &Edit<L>,
110) -> Result<(), &'static str> {
111 match edit {
112 Edit::Replace { target, with } => {
113 let (parent, index) = walk
114 .parents
115 .get(target)
116 .copied()
117 .ok_or("cannot replace root")?;
118 lang.set_child(parent, index, *with);
119 Ok(())
120 }
121 Edit::Delete { node } => {
122 let (parent, index) = walk.parents.get(node).copied().ok_or("cannot delete root")?;
123 lang.remove_child(parent, index);
124 Ok(())
125 }
126 Edit::Splice {
127 node,
128 index,
129 remove,
130 insert,
131 } => {
132 lang.splice(*node, *index, *remove, insert.clone());
133 Ok(())
134 }
135 Edit::Multi(edits) => {
136 for e in edits {
137 apply_edit(lang, walk, e)?;
138 }
139 Ok(())
140 }
141 }
142}
143
144pub(crate) fn is_replace_only<L: Lang>(edit: &Edit<L>) -> bool {
168 match edit {
169 Edit::Replace { .. } => true,
170 Edit::Multi(es) => es.iter().all(|e| matches!(e, Edit::Replace { .. })),
171 _ => false,
172 }
173}
174
175pub(crate) fn collect_footprint<L: Lang>(lang: &L, edit: &Edit<L>, out: &mut Vec<L::Id>) {
177 match edit {
178 Edit::Replace { target, .. } => collect_subtree(lang, *target, out),
179 Edit::Delete { node } => collect_subtree(lang, *node, out),
180 Edit::Splice {
181 node, index, remove, ..
182 } => {
183 let ch = lang.children(*node);
184 if *index <= ch.len() && *index + *remove <= ch.len() {
185 for &c in &ch[*index..*index + *remove] {
186 collect_subtree(lang, c, out);
187 }
188 }
189 }
190 Edit::Multi(es) => {
191 for e in es {
192 collect_footprint(lang, e, out);
193 }
194 }
195 }
196}
197
198fn collect_subtree<L: Lang>(lang: &L, id: L::Id, out: &mut Vec<L::Id>) {
199 let mut stack = vec![id];
200 while let Some(n) = stack.pop() {
201 out.push(n);
202 for &c in lang.children(n) {
203 stack.push(c);
204 }
205 }
206}
207
208pub(crate) fn collect_splice_expectations<L: Lang>(
210 lang: &L,
211 edit: &Edit<L>,
212 out: &mut Vec<Vec<L::Id>>,
213) {
214 match edit {
215 Edit::Splice {
216 node, index, remove, ..
217 } => {
218 let ch = lang.children(*node);
219 if *index <= ch.len() && *index + *remove <= ch.len() {
220 out.push(ch[*index..*index + *remove].to_vec());
221 } else {
222 out.push(Vec::new());
224 }
225 }
226 Edit::Multi(es) => {
227 for e in es {
228 collect_splice_expectations(lang, e, out);
229 }
230 }
231 _ => {}
232 }
233}
234
235pub(crate) fn verify_deferred<L: Lang>(
239 lang: &L,
240 snap: &Walk<L>,
241 edit: &Edit<L>,
242 expects: &mut &[Vec<L::Id>],
243) -> bool {
244 match edit {
245 Edit::Replace { target, .. } => match snap.parents.get(target) {
246 Some((p, _)) => lang.children(*p).contains(target),
247 None => false,
248 },
249 Edit::Delete { node } => match snap.parents.get(node) {
250 Some((p, _)) => lang.children(*p).contains(node),
251 None => false,
252 },
253 Edit::Splice {
254 node, index, remove, ..
255 } => {
256 let Some(exp) = expects.first() else {
257 return false;
258 };
259 *expects = &expects[1..];
260 let ch = lang.children(*node);
261 *index <= ch.len()
262 && *index + *remove <= ch.len()
263 && &ch[*index..*index + *remove] == exp
264 }
265 Edit::Multi(es) => es.iter().all(|e| verify_deferred(lang, snap, e, expects)),
266 }
267}
268
269pub(crate) fn apply_deferred<L: Lang>(lang: &mut L, snap: &Walk<L>, edit: &Edit<L>) {
272 match edit {
273 Edit::Replace { target, with } => {
274 if let Some((p, _)) = snap.parents.get(target) {
275 if let Some(i) = lang.children(*p).iter().position(|&c| c == *target) {
276 lang.set_child(*p, i, *with);
277 }
278 }
279 }
280 Edit::Delete { node } => {
281 if let Some((p, _)) = snap.parents.get(node) {
282 if let Some(i) = lang.children(*p).iter().position(|&c| c == *node) {
283 lang.remove_child(*p, i);
284 }
285 }
286 }
287 Edit::Splice {
288 node, index, remove, insert,
289 } => {
290 lang.splice(*node, *index, *remove, insert.clone());
291 }
292 Edit::Multi(es) => {
293 for e in es {
294 apply_deferred(lang, snap, e);
295 }
296 }
297 }
298}
299
300pub(crate) fn structural_sort_key<L: Lang>(snap: &Walk<L>, edit: &Edit<L>) -> (L::Id, usize) {
303 fn first_pos<L: Lang>(snap: &Walk<L>, e: &Edit<L>) -> Option<(L::Id, usize)> {
304 match e {
305 Edit::Splice { node, index, .. } => Some((*node, *index)),
306 Edit::Delete { node } => snap
307 .parents
308 .get(node)
309 .map(|(p, i)| (*p, *i)),
310 Edit::Replace { target, .. } => snap
311 .parents
312 .get(target)
313 .map(|(p, i)| (*p, *i)),
314 Edit::Multi(es) => es.first().and_then(|x| first_pos(snap, x)),
315 }
316 }
317 first_pos(snap, edit).unwrap_or((snap.root, 0))
318}