use ryo_mutations::basic::{AddFunctionMutation, RemoveFunctionMutation};
use ryo_mutations::MutationResult;
use ryo_source::pure::{
PureBlock, PureExpr, PureFn, PureGenerics, PureItem, PureParam, PureStmt, PureType, PureVis,
};
use ryo_symbol::SymbolKind;
use crate::engine::{ASTMutationContext, ASTRegApply};
impl ASTRegApply for AddFunctionMutation {
fn apply_to_registry(&self, ctx: &mut ASTMutationContext) -> MutationResult {
let module_id = self.parent;
if ctx.symbol_registry.kind(module_id) != Some(SymbolKind::Mod) {
return MutationResult {
mutation_type: "AddFunction".to_string(),
changes: 0,
description: format!("Target symbol {} is not a module", module_id),
};
}
let parent_path = match ctx.symbol_registry.path(module_id) {
Some(p) => p,
None => {
return MutationResult {
mutation_type: "AddFunction".to_string(),
changes: 0,
description: format!("Module {} not found in registry", module_id),
};
}
};
let exists = ctx
.symbol_registry
.iter()
.filter(|(id, _)| ctx.symbol_registry.kind(*id) == Some(SymbolKind::Function))
.any(|(_, path)| {
path.parent().as_ref() == Some(parent_path) && path.name() == self.name
});
if exists {
return MutationResult {
mutation_type: "AddFunction".to_string(),
changes: 0,
description: format!("Function '{}' already exists in module", self.name),
};
}
let func = PureFn {
name: self.name.clone(),
vis: if self.is_pub {
PureVis::Public
} else {
PureVis::Private
},
is_async: false,
is_async_inferred: false,
is_const: false,
is_unsafe: false,
generics: PureGenerics::default(),
params: self
.params
.iter()
.map(|(name, ty)| PureParam::Typed {
name: name.clone(),
ty: PureType::Path(ty.clone()),
})
.collect(),
ret: self
.return_type
.as_ref()
.map(|ty| PureType::Path(ty.clone())),
body: PureBlock {
stmts: vec![PureStmt::Expr(PureExpr::Other(self.body.clone()))],
},
attrs: Vec::new(),
abi: None,
};
let fn_path = match parent_path.child(&self.name) {
Ok(p) => p,
Err(_) => {
return MutationResult {
mutation_type: "AddFunction".to_string(),
changes: 0,
description: format!("Failed to create path for function '{}'", self.name),
};
}
};
match ctx.symbol_registry.register(fn_path, SymbolKind::Function) {
Ok(fn_id) => {
ctx.ast_registry.set(fn_id, PureItem::Fn(func));
MutationResult {
mutation_type: "AddFunction".to_string(),
changes: 1,
description: format!("Added function '{}' to module {}", self.name, module_id),
}
}
Err(e) => MutationResult {
mutation_type: "AddFunction".to_string(),
changes: 0,
description: format!("Failed to register function '{}': {:?}", self.name, e),
},
}
}
}
impl ASTRegApply for RemoveFunctionMutation {
fn apply_to_registry(&self, ctx: &mut ASTMutationContext) -> MutationResult {
let fn_id = self.symbol_id;
if ctx.symbol_registry.kind(fn_id) != Some(SymbolKind::Function) {
return MutationResult {
mutation_type: "RemoveFunction".to_string(),
changes: 0,
description: format!("Symbol {} is not a function", fn_id),
};
}
ctx.ast_registry.remove(fn_id);
MutationResult {
mutation_type: "RemoveFunction".to_string(),
changes: 1,
description: format!("Removed function {}", fn_id),
}
}
}