ryo-executor 0.1.0

[experimental] Mutation execution engine for RYO - parallel execution, conflict detection, workspace management
Documentation
//! ASTRegApply implementation for function mutations

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 {
        // Use the provided symbol_id as the parent module
        let module_id = self.parent;

        // Verify the target is a module
        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),
            };
        }

        // Check if function already exists in this module
        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),
            };
        }

        // Create the function
        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,
        };

        // Register the new function
        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 {
        // Use the provided symbol_id directly
        let fn_id = self.symbol_id;

        // Verify the target is a function
        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),
            };
        }

        // Remove from AST registry
        ctx.ast_registry.remove(fn_id);

        MutationResult {
            mutation_type: "RemoveFunction".to_string(),
            changes: 1,
            description: format!("Removed function {}", fn_id),
        }
    }
}