Skip to main content

agentic_evolve_core/crystallization/
variable_detector.rs

1//! VariableDetector — detects variable elements in code.
2
3use crate::types::pattern::{Language, PatternVariable};
4
5/// Detects which parts of code are variable (change between uses).
6#[derive(Debug, Default)]
7pub struct VariableDetector;
8
9impl VariableDetector {
10    pub fn new() -> Self {
11        Self
12    }
13
14    pub fn detect(&self, code: &str, language: &Language) -> Vec<PatternVariable> {
15        let mut variables = Vec::new();
16
17        // Detect string literals
18        let string_re = regex::Regex::new(r#""([^"]{3,})""#).unwrap();
19        for (i, cap) in string_re.captures_iter(code).enumerate() {
20            variables.push(PatternVariable {
21                name: format!("STRING_{}", i),
22                var_type: "string".to_string(),
23                pattern: None,
24                default: Some(cap[1].to_string()),
25            });
26        }
27
28        // Detect numeric literals
29        let num_re = regex::Regex::new(r"\b(\d{2,})\b").unwrap();
30        for (i, cap) in num_re.captures_iter(code).enumerate() {
31            variables.push(PatternVariable {
32                name: format!("NUMBER_{}", i),
33                var_type: "number".to_string(),
34                pattern: Some(r"\d+".to_string()),
35                default: Some(cap[1].to_string()),
36            });
37        }
38
39        // Detect type names (language-specific)
40        match language {
41            Language::Rust => {
42                let type_re = regex::Regex::new(r"\b([A-Z][a-zA-Z0-9]+)\b").unwrap();
43                let mut seen = std::collections::HashSet::new();
44                for cap in type_re.captures_iter(code) {
45                    let name = &cap[1];
46                    if !is_common_type(name) && seen.insert(name.to_string()) {
47                        variables.push(PatternVariable {
48                            name: format!("TYPE_{name}"),
49                            var_type: "type".to_string(),
50                            pattern: Some(r"[A-Z]\w+".to_string()),
51                            default: Some(name.to_string()),
52                        });
53                    }
54                }
55            }
56            Language::Python => {
57                let type_re = regex::Regex::new(r"\b([A-Z][a-zA-Z0-9]+)\b").unwrap();
58                let mut seen = std::collections::HashSet::new();
59                for cap in type_re.captures_iter(code) {
60                    let name = &cap[1];
61                    if !is_common_python_type(name) && seen.insert(name.to_string()) {
62                        variables.push(PatternVariable {
63                            name: format!("TYPE_{name}"),
64                            var_type: "type".to_string(),
65                            pattern: Some(r"[A-Z]\w+".to_string()),
66                            default: Some(name.to_string()),
67                        });
68                    }
69                }
70            }
71            _ => {}
72        }
73
74        variables
75    }
76}
77
78fn is_common_type(name: &str) -> bool {
79    matches!(
80        name,
81        "String"
82            | "Vec"
83            | "HashMap"
84            | "HashSet"
85            | "Option"
86            | "Result"
87            | "Box"
88            | "Arc"
89            | "Rc"
90            | "Mutex"
91            | "RwLock"
92            | "Cell"
93            | "RefCell"
94            | "Self"
95            | "Ok"
96            | "Err"
97            | "Some"
98            | "None"
99            | "Default"
100            | "Debug"
101            | "Clone"
102            | "Copy"
103            | "Send"
104            | "Sync"
105            | "Display"
106            | "Error"
107            | "Serialize"
108            | "Deserialize"
109            | "Value"
110            | "Path"
111            | "PathBuf"
112    )
113}
114
115fn is_common_python_type(name: &str) -> bool {
116    matches!(
117        name,
118        "True"
119            | "False"
120            | "None"
121            | "List"
122            | "Dict"
123            | "Set"
124            | "Tuple"
125            | "Optional"
126            | "Union"
127            | "Any"
128            | "Type"
129            | "Callable"
130            | "Iterator"
131            | "Exception"
132            | "ValueError"
133            | "TypeError"
134            | "KeyError"
135    )
136}