Skip to main content

ryo_executor/engine/impls/
function.rs

1//! ASTRegApply implementation for function mutations
2
3use ryo_mutations::basic::{AddFunctionMutation, RemoveFunctionMutation};
4use ryo_mutations::MutationResult;
5use ryo_source::pure::{
6    PureBlock, PureExpr, PureFn, PureGenerics, PureItem, PureParam, PureStmt, PureType, PureVis,
7};
8use ryo_symbol::SymbolKind;
9
10use crate::engine::{ASTMutationContext, ASTRegApply};
11
12impl ASTRegApply for AddFunctionMutation {
13    fn apply_to_registry(&self, ctx: &mut ASTMutationContext) -> MutationResult {
14        // Use the provided symbol_id as the parent module
15        let module_id = self.parent;
16
17        // Verify the target is a module
18        if ctx.symbol_registry.kind(module_id) != Some(SymbolKind::Mod) {
19            return MutationResult {
20                mutation_type: "AddFunction".to_string(),
21                changes: 0,
22                description: format!("Target symbol {} is not a module", module_id),
23            };
24        }
25
26        // Check if function already exists in this module
27        let parent_path = match ctx.symbol_registry.path(module_id) {
28            Some(p) => p,
29            None => {
30                return MutationResult {
31                    mutation_type: "AddFunction".to_string(),
32                    changes: 0,
33                    description: format!("Module {} not found in registry", module_id),
34                };
35            }
36        };
37
38        let exists = ctx
39            .symbol_registry
40            .iter()
41            .filter(|(id, _)| ctx.symbol_registry.kind(*id) == Some(SymbolKind::Function))
42            .any(|(_, path)| {
43                path.parent().as_ref() == Some(parent_path) && path.name() == self.name
44            });
45
46        if exists {
47            return MutationResult {
48                mutation_type: "AddFunction".to_string(),
49                changes: 0,
50                description: format!("Function '{}' already exists in module", self.name),
51            };
52        }
53
54        // Create the function
55        let func = PureFn {
56            name: self.name.clone(),
57            vis: if self.is_pub {
58                PureVis::Public
59            } else {
60                PureVis::Private
61            },
62            is_async: false,
63            is_async_inferred: false,
64            is_const: false,
65            is_unsafe: false,
66            generics: PureGenerics::default(),
67            params: self
68                .params
69                .iter()
70                .map(|(name, ty)| PureParam::Typed {
71                    name: name.clone(),
72                    ty: PureType::Path(ty.clone()),
73                })
74                .collect(),
75            ret: self
76                .return_type
77                .as_ref()
78                .map(|ty| PureType::Path(ty.clone())),
79            body: PureBlock {
80                stmts: vec![PureStmt::Expr(PureExpr::Other(self.body.clone()))],
81            },
82            attrs: Vec::new(),
83            abi: None,
84        };
85
86        // Register the new function
87        let fn_path = match parent_path.child(&self.name) {
88            Ok(p) => p,
89            Err(_) => {
90                return MutationResult {
91                    mutation_type: "AddFunction".to_string(),
92                    changes: 0,
93                    description: format!("Failed to create path for function '{}'", self.name),
94                };
95            }
96        };
97
98        match ctx.symbol_registry.register(fn_path, SymbolKind::Function) {
99            Ok(fn_id) => {
100                ctx.ast_registry.set(fn_id, PureItem::Fn(func));
101                MutationResult {
102                    mutation_type: "AddFunction".to_string(),
103                    changes: 1,
104                    description: format!("Added function '{}' to module {}", self.name, module_id),
105                }
106            }
107            Err(e) => MutationResult {
108                mutation_type: "AddFunction".to_string(),
109                changes: 0,
110                description: format!("Failed to register function '{}': {:?}", self.name, e),
111            },
112        }
113    }
114}
115
116impl ASTRegApply for RemoveFunctionMutation {
117    fn apply_to_registry(&self, ctx: &mut ASTMutationContext) -> MutationResult {
118        // Use the provided symbol_id directly
119        let fn_id = self.symbol_id;
120
121        // Verify the target is a function
122        if ctx.symbol_registry.kind(fn_id) != Some(SymbolKind::Function) {
123            return MutationResult {
124                mutation_type: "RemoveFunction".to_string(),
125                changes: 0,
126                description: format!("Symbol {} is not a function", fn_id),
127            };
128        }
129
130        // Remove from AST registry
131        ctx.ast_registry.remove(fn_id);
132
133        MutationResult {
134            mutation_type: "RemoveFunction".to_string(),
135            changes: 1,
136            description: format!("Removed function {}", fn_id),
137        }
138    }
139}