Skip to main content

ryo_mutations/basic/
function.rs

1//! Function mutations: AddFunctionMutation, RemoveFunctionMutation
2
3use ryo_source::pure::PureFile;
4use ryo_symbol::SymbolId;
5
6use crate::{Mutation, ValidationIssue, ValidationResult};
7
8/// Add a new function to the file
9#[derive(Debug, Clone)]
10pub struct AddFunctionMutation {
11    /// Parent module SymbolId
12    pub parent: SymbolId,
13    pub name: String,
14    pub params: Vec<(String, String)>, // (name, type)
15    pub return_type: Option<String>,
16    pub body: String, // Simple expression body
17    pub is_pub: bool,
18}
19
20impl AddFunctionMutation {
21    pub fn new(parent: SymbolId, name: impl Into<String>) -> Self {
22        Self {
23            parent,
24            name: name.into(),
25            params: Vec::new(),
26            return_type: None,
27            body: "todo!()".to_string(),
28            is_pub: false,
29        }
30    }
31
32    pub fn with_params(mut self, params: Vec<(String, String)>) -> Self {
33        self.params = params;
34        self
35    }
36
37    pub fn with_return_type(mut self, ty: impl Into<String>) -> Self {
38        self.return_type = Some(ty.into());
39        self
40    }
41
42    pub fn with_body(mut self, body: impl Into<String>) -> Self {
43        self.body = body.into();
44        self
45    }
46
47    pub fn public(mut self) -> Self {
48        self.is_pub = true;
49        self
50    }
51}
52
53impl Mutation for AddFunctionMutation {
54    fn validate(&self, file: &PureFile) -> ValidationResult {
55        let mut result = ValidationResult::new();
56
57        // Check if function already exists
58        if file.find_fn(&self.name).is_some() {
59            result.add(ValidationIssue::duplicate_symbol(&self.name));
60        }
61
62        result
63    }
64
65    fn describe(&self) -> String {
66        let vis = if self.is_pub { "pub " } else { "" };
67        let ret = self
68            .return_type
69            .as_ref()
70            .map(|t| format!(" -> {}", t))
71            .unwrap_or_default();
72        format!(
73            "Add {}fn {}(){} {{ {} }} to {}",
74            vis, self.name, ret, self.body, self.parent
75        )
76    }
77
78    fn mutation_type(&self) -> &'static str {
79        "AddFunction"
80    }
81
82    fn box_clone(&self) -> Box<dyn Mutation> {
83        Box::new(self.clone())
84    }
85}
86
87/// Remove a function from the file
88#[derive(Debug, Clone)]
89pub struct RemoveFunctionMutation {
90    pub symbol_id: SymbolId,
91}
92
93impl RemoveFunctionMutation {
94    pub fn new(symbol_id: SymbolId) -> Self {
95        Self { symbol_id }
96    }
97}
98
99impl Mutation for RemoveFunctionMutation {
100    fn validate(&self, _file: &PureFile) -> ValidationResult {
101        // Validation is minimal since we rely on symbol_id (O(1) lookup)
102        // Actual validation happens during AST execution via ASTRegApply
103        ValidationResult::new()
104    }
105
106    fn describe(&self) -> String {
107        format!("Remove function {}", self.symbol_id)
108    }
109
110    fn mutation_type(&self) -> &'static str {
111        "RemoveFunction"
112    }
113
114    fn box_clone(&self) -> Box<dyn Mutation> {
115        Box::new(self.clone())
116    }
117}