Skip to main content

ryo_executor/engine/impls/
debugger.rs

1//! V2 ASTRegApply implementations for debugger mutations
2//!
3//! # Classification: Primitive
4//!
5//! These are fundamental expression transformation operations:
6//! - DbgWrap: Wrap expressions in dbg!() macro
7//! - InsertInspect: Insert .inspect() calls for iterator debugging
8//! - RemoveDebugLogs: Remove debug logging statements
9
10use ryo_mutations::debugger::{DbgWrapMutation, InsertInspectMutation, RemoveDebugLogsMutation};
11use ryo_mutations::MutationResult;
12use ryo_source::pure::PureItem;
13use ryo_symbol::SymbolKind;
14
15use crate::engine::{ASTMutationContext, ASTRegApply};
16
17impl ASTRegApply for DbgWrapMutation {
18    fn apply_to_registry(&self, ctx: &mut ASTMutationContext) -> MutationResult {
19        let mut total_changes = 0;
20
21        // Collect function IDs first to avoid borrow issues
22        let fn_ids: Vec<_> = ctx
23            .symbol_registry
24            .iter()
25            .filter(|(id, _)| ctx.symbol_registry.kind(*id) == Some(SymbolKind::Function))
26            .map(|(id, _)| id)
27            .collect();
28
29        for fn_id in fn_ids {
30            if let Some(PureItem::Fn(func)) = ctx.ast_registry.get(fn_id) {
31                let (new_func, count) = self.transform_fn(func);
32                if count > 0 {
33                    ctx.set_ast(fn_id, PureItem::Fn(new_func));
34                    total_changes += count;
35                }
36            }
37        }
38
39        // Also process methods in impl blocks
40        let impl_ids: Vec<_> = ctx
41            .symbol_registry
42            .iter()
43            .filter(|(id, _)| ctx.symbol_registry.kind(*id) == Some(SymbolKind::Impl))
44            .map(|(id, _)| id)
45            .collect();
46
47        for impl_id in impl_ids {
48            if let Some(PureItem::Impl(imp)) = ctx.ast_registry.get(impl_id) {
49                let mut new_impl = imp.clone();
50                let mut impl_changes = 0;
51
52                for impl_item in &mut new_impl.items {
53                    if let ryo_source::pure::PureImplItem::Fn(method) = impl_item {
54                        let (new_method, count) = self.transform_fn(method);
55                        if count > 0 {
56                            *method = new_method;
57                            impl_changes += count;
58                        }
59                    }
60                }
61
62                if impl_changes > 0 {
63                    ctx.set_ast(impl_id, PureItem::Impl(new_impl));
64                    total_changes += impl_changes;
65                }
66            }
67        }
68
69        MutationResult {
70            mutation_type: "DbgWrap".to_string(),
71            changes: total_changes,
72            description: if total_changes > 0 {
73                format!("Wrapped {} expression(s) with dbg!()", total_changes)
74            } else {
75                "No expressions wrapped".to_string()
76            },
77        }
78    }
79}
80
81impl ASTRegApply for InsertInspectMutation {
82    fn apply_to_registry(&self, ctx: &mut ASTMutationContext) -> MutationResult {
83        let mut total_changes = 0;
84
85        // Collect function IDs
86        let fn_ids: Vec<_> = ctx
87            .symbol_registry
88            .iter()
89            .filter(|(id, path)| {
90                if ctx.symbol_registry.kind(*id) != Some(SymbolKind::Function) {
91                    return false;
92                }
93                // Apply in_function filter if specified
94                if let Some(ref target) = self.in_function {
95                    return path.name() == target;
96                }
97                true
98            })
99            .map(|(id, _)| id)
100            .collect();
101
102        for fn_id in fn_ids {
103            if let Some(PureItem::Fn(func)) = ctx.ast_registry.get(fn_id) {
104                let (new_func, count) = self.transform_fn(func);
105                if count > 0 {
106                    ctx.set_ast(fn_id, PureItem::Fn(new_func));
107                    total_changes += count;
108                }
109            }
110        }
111
112        // Also process impl blocks
113        let impl_ids: Vec<_> = ctx
114            .symbol_registry
115            .iter()
116            .filter(|(id, _)| ctx.symbol_registry.kind(*id) == Some(SymbolKind::Impl))
117            .map(|(id, _)| id)
118            .collect();
119
120        for impl_id in impl_ids {
121            if let Some(PureItem::Impl(imp)) = ctx.ast_registry.get(impl_id) {
122                let mut new_impl = imp.clone();
123                let mut impl_changes = 0;
124
125                for impl_item in &mut new_impl.items {
126                    if let ryo_source::pure::PureImplItem::Fn(method) = impl_item {
127                        // Apply in_function filter
128                        if let Some(ref target) = self.in_function {
129                            if &method.name != target {
130                                continue;
131                            }
132                        }
133
134                        let (new_method, count) = self.transform_fn(method);
135                        if count > 0 {
136                            *method = new_method;
137                            impl_changes += count;
138                        }
139                    }
140                }
141
142                if impl_changes > 0 {
143                    ctx.set_ast(impl_id, PureItem::Impl(new_impl));
144                    total_changes += impl_changes;
145                }
146            }
147        }
148
149        MutationResult {
150            mutation_type: "InsertInspect".to_string(),
151            changes: total_changes,
152            description: if total_changes > 0 {
153                format!("Inserted {} .inspect() call(s)", total_changes)
154            } else {
155                "No .inspect() calls inserted".to_string()
156            },
157        }
158    }
159}
160
161impl ASTRegApply for RemoveDebugLogsMutation {
162    fn apply_to_registry(&self, ctx: &mut ASTMutationContext) -> MutationResult {
163        let mut total_changes = 0;
164
165        // Collect function IDs
166        let fn_ids: Vec<_> = ctx
167            .symbol_registry
168            .iter()
169            .filter(|(id, _)| ctx.symbol_registry.kind(*id) == Some(SymbolKind::Function))
170            .map(|(id, _)| id)
171            .collect();
172
173        for fn_id in fn_ids {
174            if let Some(PureItem::Fn(func)) = ctx.ast_registry.get(fn_id) {
175                let (new_func, count) = self.transform_fn(func);
176                if count > 0 {
177                    ctx.set_ast(fn_id, PureItem::Fn(new_func));
178                    total_changes += count;
179                }
180            }
181        }
182
183        // Also process impl blocks
184        let impl_ids: Vec<_> = ctx
185            .symbol_registry
186            .iter()
187            .filter(|(id, _)| ctx.symbol_registry.kind(*id) == Some(SymbolKind::Impl))
188            .map(|(id, _)| id)
189            .collect();
190
191        for impl_id in impl_ids {
192            if let Some(PureItem::Impl(imp)) = ctx.ast_registry.get(impl_id) {
193                let mut new_impl = imp.clone();
194                let mut impl_changes = 0;
195
196                for impl_item in &mut new_impl.items {
197                    if let ryo_source::pure::PureImplItem::Fn(method) = impl_item {
198                        let (new_method, count) = self.transform_fn(method);
199                        if count > 0 {
200                            *method = new_method;
201                            impl_changes += count;
202                        }
203                    }
204                }
205
206                if impl_changes > 0 {
207                    ctx.set_ast(impl_id, PureItem::Impl(new_impl));
208                    total_changes += impl_changes;
209                }
210            }
211        }
212
213        MutationResult {
214            mutation_type: "RemoveDebugLogs".to_string(),
215            changes: total_changes,
216            description: if total_changes > 0 {
217                format!("Removed {} debug log(s)", total_changes)
218            } else {
219                "No debug logs removed".to_string()
220            },
221        }
222    }
223}