use ryo_source::pure::PureExpr;
use ryo_symbol::SymbolId;
use crate::Mutation;
#[derive(Debug, Clone)]
pub struct IntroduceVariableMutation {
pub target_expr: PureExpr,
pub var_name: String,
pub target_fn: Option<SymbolId>,
pub is_mut: bool,
}
impl IntroduceVariableMutation {
pub fn new(target_expr: PureExpr, var_name: impl Into<String>) -> Self {
Self {
target_expr,
var_name: var_name.into(),
target_fn: None,
is_mut: false,
}
}
pub fn in_function(mut self, id: SymbolId) -> Self {
self.target_fn = Some(id);
self
}
pub fn mutable(mut self) -> Self {
self.is_mut = true;
self
}
}
impl Mutation for IntroduceVariableMutation {
fn describe(&self) -> String {
format!("Introduce variable '{}'", self.var_name)
}
fn mutation_type(&self) -> &'static str {
"IntroduceVariable"
}
fn box_clone(&self) -> Box<dyn Mutation> {
Box::new(self.clone())
}
}
#[derive(Debug, Clone, Default)]
pub struct FindDuplicateExpressions {
pub min_complexity: usize,
pub min_occurrences: usize,
}
impl FindDuplicateExpressions {
pub fn new() -> Self {
Self {
min_complexity: 3,
min_occurrences: 2,
}
}
pub fn complexity(expr: &PureExpr) -> usize {
let mut count = 1;
match expr {
PureExpr::Binary { left, right, .. } => {
count += Self::complexity(left) + Self::complexity(right);
}
PureExpr::Unary { expr: inner, .. } => {
count += Self::complexity(inner);
}
PureExpr::Call { func, args } => {
count += Self::complexity(func);
for arg in args {
count += Self::complexity(arg);
}
}
PureExpr::MethodCall { receiver, args, .. } => {
count += Self::complexity(receiver);
for arg in args {
count += Self::complexity(arg);
}
}
PureExpr::Field { expr: inner, .. } => {
count += Self::complexity(inner);
}
PureExpr::Index { expr: inner, index } => {
count += Self::complexity(inner) + Self::complexity(index);
}
_ => {}
}
count
}
}
#[cfg(test)]
mod tests {
use super::*;
fn make_binary_expr() -> PureExpr {
PureExpr::Binary {
op: "+".to_string(),
left: Box::new(PureExpr::Path("a".to_string())),
right: Box::new(PureExpr::Binary {
op: "*".to_string(),
left: Box::new(PureExpr::Path("b".to_string())),
right: Box::new(PureExpr::Path("c".to_string())),
}),
}
}
#[test]
fn test_complexity() {
let simple = PureExpr::Path("x".to_string());
assert_eq!(FindDuplicateExpressions::complexity(&simple), 1);
let complex = make_binary_expr();
assert_eq!(FindDuplicateExpressions::complexity(&complex), 5); }
}