1use airl_ir::module::Module;
6
7use crate::ops::{Patch, PatchOp};
8use crate::traverse;
9use crate::PatchError;
10
11pub fn invert_patch(module: &Module, patch: &Patch) -> Result<Patch, PatchError> {
16 let mut inverse_ops = Vec::new();
17
18 for op in &patch.operations {
19 let inv = invert_op(module, op)?;
20 inverse_ops.push(inv);
21 }
22
23 inverse_ops.reverse();
25
26 Ok(Patch {
27 id: format!("inv_{}", patch.id),
28 parent_version: String::new(), operations: inverse_ops,
30 rationale: format!("Inverse of: {}", patch.rationale),
31 author: patch.author.clone(),
32 })
33}
34
35fn invert_op(module: &Module, op: &PatchOp) -> Result<PatchOp, PatchError> {
36 match op {
37 PatchOp::ReplaceNode { target, .. } => {
38 let func = traverse::find_containing_function(module, target).ok_or(
40 PatchError::NodeNotFound {
41 node_id: target.to_string(),
42 },
43 )?;
44 let original_node =
45 traverse::find_node(&func.body, target).ok_or(PatchError::NodeNotFound {
46 node_id: target.to_string(),
47 })?;
48
49 Ok(PatchOp::ReplaceNode {
50 target: target.clone(),
54 replacement: original_node.clone(),
55 })
56 }
57
58 PatchOp::AddFunction { func } => Ok(PatchOp::RemoveFunction {
59 func_id: func.id.clone(),
60 }),
61
62 PatchOp::RemoveFunction { func_id } => {
63 let func = module
65 .find_function_by_id(func_id)
66 .ok_or(PatchError::FunctionNotFound {
67 func_id: func_id.to_string(),
68 })?;
69 Ok(PatchOp::AddFunction { func: func.clone() })
70 }
71
72 PatchOp::AddImport { import } => Ok(PatchOp::RemoveImport {
73 import: import.clone(),
74 }),
75
76 PatchOp::RemoveImport { import } => Ok(PatchOp::AddImport {
77 import: import.clone(),
78 }),
79
80 PatchOp::RenameSymbol {
81 old_name,
82 new_name,
83 scope,
84 } => Ok(PatchOp::RenameSymbol {
85 old_name: new_name.clone(),
86 new_name: old_name.clone(),
87 scope: scope.clone(),
88 }),
89
90 PatchOp::AddEffect { func_id, effect } => Ok(PatchOp::RemoveEffect {
91 func_id: func_id.clone(),
92 effect: effect.clone(),
93 }),
94
95 PatchOp::RemoveEffect { func_id, effect } => Ok(PatchOp::AddEffect {
96 func_id: func_id.clone(),
97 effect: effect.clone(),
98 }),
99 }
100}