use airl_ir::module::Module;
use crate::ops::{Patch, PatchOp};
use crate::traverse;
use crate::PatchError;
pub fn validate_patch(module: &Module, patch: &Patch) -> Result<(), PatchError> {
for (i, op) in patch.operations.iter().enumerate() {
validate_op(module, op).map_err(|e| PatchError::ValidationFailed {
op_index: i,
message: e.to_string(),
})?;
}
Ok(())
}
fn validate_op(module: &Module, op: &PatchOp) -> Result<(), PatchError> {
match op {
PatchOp::ReplaceNode { target, .. } => {
if traverse::find_containing_function(module, target).is_none() {
return Err(PatchError::NodeNotFound {
node_id: target.to_string(),
});
}
Ok(())
}
PatchOp::RemoveFunction { func_id } => {
if module.find_function_by_id(func_id).is_none() {
return Err(PatchError::FunctionNotFound {
func_id: func_id.to_string(),
});
}
Ok(())
}
PatchOp::AddFunction { func } => {
if module.find_function(&func.name).is_some() {
return Err(PatchError::DuplicateFunction {
name: func.name.clone(),
});
}
Ok(())
}
PatchOp::AddEffect { func_id, .. } | PatchOp::RemoveEffect { func_id, .. } => {
if module.find_function_by_id(func_id).is_none() {
return Err(PatchError::FunctionNotFound {
func_id: func_id.to_string(),
});
}
Ok(())
}
PatchOp::RenameSymbol { .. } | PatchOp::AddImport { .. } | PatchOp::RemoveImport { .. } => {
Ok(())
}
}
}