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                    is_mut: false,
74                    pat: None,
75                })
76                .collect(),
77            ret: self
78                .return_type
79                .as_ref()
80                .map(|ty| PureType::Path(ty.clone())),
81            body: PureBlock {
82                stmts: vec![PureStmt::Expr(PureExpr::Other(self.body.clone()))],
83            },
84            attrs: Vec::new(),
85            abi: None,
86        };
87
88        // Register the new function
89        let fn_path = match parent_path.child(&self.name) {
90            Ok(p) => p,
91            Err(_) => {
92                return MutationResult {
93                    mutation_type: "AddFunction".to_string(),
94                    changes: 0,
95                    description: format!("Failed to create path for function '{}'", self.name),
96                };
97            }
98        };
99
100        match ctx.symbol_registry.register(fn_path, SymbolKind::Function) {
101            Ok(fn_id) => {
102                ctx.ast_registry.set(fn_id, PureItem::Fn(func));
103                MutationResult {
104                    mutation_type: "AddFunction".to_string(),
105                    changes: 1,
106                    description: format!("Added function '{}' to module {}", self.name, module_id),
107                }
108            }
109            Err(e) => MutationResult {
110                mutation_type: "AddFunction".to_string(),
111                changes: 0,
112                description: format!("Failed to register function '{}': {:?}", self.name, e),
113            },
114        }
115    }
116}
117
118impl ASTRegApply for RemoveFunctionMutation {
119    fn apply_to_registry(&self, ctx: &mut ASTMutationContext) -> MutationResult {
120        // Use the provided symbol_id directly
121        let fn_id = self.symbol_id;
122
123        // Verify the target is a function
124        if ctx.symbol_registry.kind(fn_id) != Some(SymbolKind::Function) {
125            return MutationResult {
126                mutation_type: "RemoveFunction".to_string(),
127                changes: 0,
128                description: format!("Symbol {} is not a function", fn_id),
129            };
130        }
131
132        // Remove from AST registry
133        ctx.ast_registry.remove(fn_id);
134
135        MutationResult {
136            mutation_type: "RemoveFunction".to_string(),
137            changes: 1,
138            description: format!("Removed function {}", fn_id),
139        }
140    }
141}