1use airl_ir::module::Module;
4
5use crate::ops::{Patch, PatchOp};
6use crate::traverse;
7use crate::PatchError;
8
9pub fn validate_patch(module: &Module, patch: &Patch) -> Result<(), PatchError> {
12 for (i, op) in patch.operations.iter().enumerate() {
13 validate_op(module, op).map_err(|e| PatchError::ValidationFailed {
14 op_index: i,
15 message: e.to_string(),
16 })?;
17 }
18 Ok(())
19}
20
21fn validate_op(module: &Module, op: &PatchOp) -> Result<(), PatchError> {
22 match op {
23 PatchOp::ReplaceNode { target, .. } => {
24 if traverse::find_containing_function(module, target).is_none() {
26 return Err(PatchError::NodeNotFound {
27 node_id: target.to_string(),
28 });
29 }
30 Ok(())
31 }
32 PatchOp::RemoveFunction { func_id } => {
33 if module.find_function_by_id(func_id).is_none() {
34 return Err(PatchError::FunctionNotFound {
35 func_id: func_id.to_string(),
36 });
37 }
38 Ok(())
39 }
40 PatchOp::AddFunction { func } => {
41 if module.find_function(&func.name).is_some() {
43 return Err(PatchError::DuplicateFunction {
44 name: func.name.clone(),
45 });
46 }
47 Ok(())
48 }
49 PatchOp::AddEffect { func_id, .. } | PatchOp::RemoveEffect { func_id, .. } => {
50 if module.find_function_by_id(func_id).is_none() {
51 return Err(PatchError::FunctionNotFound {
52 func_id: func_id.to_string(),
53 });
54 }
55 Ok(())
56 }
57 PatchOp::RenameSymbol { .. } | PatchOp::AddImport { .. } | PatchOp::RemoveImport { .. } => {
59 Ok(())
60 }
61 }
62}