ryo-executor 0.1.0

[experimental] Mutation execution engine for RYO - parallel execution, conflict detection, workspace management
Documentation
//! V2 ASTRegApply implementations for debugger mutations
//!
//! # Classification: Primitive
//!
//! These are fundamental expression transformation operations:
//! - DbgWrap: Wrap expressions in dbg!() macro
//! - InsertInspect: Insert .inspect() calls for iterator debugging
//! - RemoveDebugLogs: Remove debug logging statements

use ryo_mutations::debugger::{DbgWrapMutation, InsertInspectMutation, RemoveDebugLogsMutation};
use ryo_mutations::MutationResult;
use ryo_source::pure::PureItem;
use ryo_symbol::SymbolKind;

use crate::engine::{ASTMutationContext, ASTRegApply};

impl ASTRegApply for DbgWrapMutation {
    fn apply_to_registry(&self, ctx: &mut ASTMutationContext) -> MutationResult {
        let mut total_changes = 0;

        // Collect function IDs first to avoid borrow issues
        let fn_ids: Vec<_> = ctx
            .symbol_registry
            .iter()
            .filter(|(id, _)| ctx.symbol_registry.kind(*id) == Some(SymbolKind::Function))
            .map(|(id, _)| id)
            .collect();

        for fn_id in fn_ids {
            if let Some(PureItem::Fn(func)) = ctx.ast_registry.get(fn_id) {
                let (new_func, count) = self.transform_fn(func);
                if count > 0 {
                    ctx.set_ast(fn_id, PureItem::Fn(new_func));
                    total_changes += count;
                }
            }
        }

        // Also process methods in impl blocks
        let impl_ids: Vec<_> = ctx
            .symbol_registry
            .iter()
            .filter(|(id, _)| ctx.symbol_registry.kind(*id) == Some(SymbolKind::Impl))
            .map(|(id, _)| id)
            .collect();

        for impl_id in impl_ids {
            if let Some(PureItem::Impl(imp)) = ctx.ast_registry.get(impl_id) {
                let mut new_impl = imp.clone();
                let mut impl_changes = 0;

                for impl_item in &mut new_impl.items {
                    if let ryo_source::pure::PureImplItem::Fn(method) = impl_item {
                        let (new_method, count) = self.transform_fn(method);
                        if count > 0 {
                            *method = new_method;
                            impl_changes += count;
                        }
                    }
                }

                if impl_changes > 0 {
                    ctx.set_ast(impl_id, PureItem::Impl(new_impl));
                    total_changes += impl_changes;
                }
            }
        }

        MutationResult {
            mutation_type: "DbgWrap".to_string(),
            changes: total_changes,
            description: if total_changes > 0 {
                format!("Wrapped {} expression(s) with dbg!()", total_changes)
            } else {
                "No expressions wrapped".to_string()
            },
        }
    }
}

impl ASTRegApply for InsertInspectMutation {
    fn apply_to_registry(&self, ctx: &mut ASTMutationContext) -> MutationResult {
        let mut total_changes = 0;

        // Collect function IDs
        let fn_ids: Vec<_> = ctx
            .symbol_registry
            .iter()
            .filter(|(id, path)| {
                if ctx.symbol_registry.kind(*id) != Some(SymbolKind::Function) {
                    return false;
                }
                // Apply in_function filter if specified
                if let Some(ref target) = self.in_function {
                    return path.name() == target;
                }
                true
            })
            .map(|(id, _)| id)
            .collect();

        for fn_id in fn_ids {
            if let Some(PureItem::Fn(func)) = ctx.ast_registry.get(fn_id) {
                let (new_func, count) = self.transform_fn(func);
                if count > 0 {
                    ctx.set_ast(fn_id, PureItem::Fn(new_func));
                    total_changes += count;
                }
            }
        }

        // Also process impl blocks
        let impl_ids: Vec<_> = ctx
            .symbol_registry
            .iter()
            .filter(|(id, _)| ctx.symbol_registry.kind(*id) == Some(SymbolKind::Impl))
            .map(|(id, _)| id)
            .collect();

        for impl_id in impl_ids {
            if let Some(PureItem::Impl(imp)) = ctx.ast_registry.get(impl_id) {
                let mut new_impl = imp.clone();
                let mut impl_changes = 0;

                for impl_item in &mut new_impl.items {
                    if let ryo_source::pure::PureImplItem::Fn(method) = impl_item {
                        // Apply in_function filter
                        if let Some(ref target) = self.in_function {
                            if &method.name != target {
                                continue;
                            }
                        }

                        let (new_method, count) = self.transform_fn(method);
                        if count > 0 {
                            *method = new_method;
                            impl_changes += count;
                        }
                    }
                }

                if impl_changes > 0 {
                    ctx.set_ast(impl_id, PureItem::Impl(new_impl));
                    total_changes += impl_changes;
                }
            }
        }

        MutationResult {
            mutation_type: "InsertInspect".to_string(),
            changes: total_changes,
            description: if total_changes > 0 {
                format!("Inserted {} .inspect() call(s)", total_changes)
            } else {
                "No .inspect() calls inserted".to_string()
            },
        }
    }
}

impl ASTRegApply for RemoveDebugLogsMutation {
    fn apply_to_registry(&self, ctx: &mut ASTMutationContext) -> MutationResult {
        let mut total_changes = 0;

        // Collect function IDs
        let fn_ids: Vec<_> = ctx
            .symbol_registry
            .iter()
            .filter(|(id, _)| ctx.symbol_registry.kind(*id) == Some(SymbolKind::Function))
            .map(|(id, _)| id)
            .collect();

        for fn_id in fn_ids {
            if let Some(PureItem::Fn(func)) = ctx.ast_registry.get(fn_id) {
                let (new_func, count) = self.transform_fn(func);
                if count > 0 {
                    ctx.set_ast(fn_id, PureItem::Fn(new_func));
                    total_changes += count;
                }
            }
        }

        // Also process impl blocks
        let impl_ids: Vec<_> = ctx
            .symbol_registry
            .iter()
            .filter(|(id, _)| ctx.symbol_registry.kind(*id) == Some(SymbolKind::Impl))
            .map(|(id, _)| id)
            .collect();

        for impl_id in impl_ids {
            if let Some(PureItem::Impl(imp)) = ctx.ast_registry.get(impl_id) {
                let mut new_impl = imp.clone();
                let mut impl_changes = 0;

                for impl_item in &mut new_impl.items {
                    if let ryo_source::pure::PureImplItem::Fn(method) = impl_item {
                        let (new_method, count) = self.transform_fn(method);
                        if count > 0 {
                            *method = new_method;
                            impl_changes += count;
                        }
                    }
                }

                if impl_changes > 0 {
                    ctx.set_ast(impl_id, PureItem::Impl(new_impl));
                    total_changes += impl_changes;
                }
            }
        }

        MutationResult {
            mutation_type: "RemoveDebugLogs".to_string(),
            changes: total_changes,
            description: if total_changes > 0 {
                format!("Removed {} debug log(s)", total_changes)
            } else {
                "No debug logs removed".to_string()
            },
        }
    }
}