marauders 0.0.13

A tool for hand-crafted mutation analysis and management
Documentation
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub enum Language {
    Rocq,
    Haskell,
    Racket,
    Rust,
    OCaml,
    Python,
    #[serde(untagged)]
    Custom(CustomLanguage),
}

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct CustomLanguage {
    pub name: String,
    pub extension: String,
    pub comment_begin: String,
    pub comment_end: String,
    pub mutation_marker: String,
}

impl Language {
    pub fn file_extension(&self) -> &str {
        match self {
            Language::Rocq => "v",
            Language::Haskell => "hs",
            Language::Racket => "rkt",
            Language::Rust => "rs",
            Language::OCaml => "ml",
            Language::Python => "py",
            Language::Custom(custom) => custom.extension.as_str(),
        }
    }

    pub fn extension_to_language(
        ext: &str,
        custom_languages: &Vec<CustomLanguage>,
    ) -> Option<Language> {
        match ext {
            "v" => Some(Language::Rocq),
            "hs" => Some(Language::Haskell),
            "rkt" => Some(Language::Racket),
            "rs" => Some(Language::Rust),
            "ml" => Some(Language::OCaml),
            "py" => Some(Language::Python),
            _ => {
                for custom in custom_languages {
                    if custom.extension == ext {
                        return Some(Language::Custom(custom.clone()));
                    }
                }
                None
            }
        }
    }

    pub fn name_to_language(
        name: &str,
        custom_languages: &Vec<CustomLanguage>,
    ) -> Option<Language> {
        match name.to_lowercase().as_str() {
            "rocq" => Some(Language::Rocq),
            "haskell" => Some(Language::Haskell),
            "racket" => Some(Language::Racket),
            "rust" => Some(Language::Rust),
            "ocaml" => Some(Language::OCaml),
            "python" => Some(Language::Python),
            _ => {
                for custom in custom_languages {
                    if custom.name == name {
                        return Some(Language::Custom(custom.clone()));
                    }
                }
                log::warn!("unknown language: {}", name);
                None
            }
        }
    }

    pub fn comment_begin(&self) -> String {
        match self {
            Language::Rocq => "(*".to_string(),
            Language::Haskell => "{-".to_string(),
            Language::Racket => "#|".to_string(),
            Language::Rust => "/*".to_string(),
            Language::OCaml => "(*".to_string(),
            Language::Python => r#"""""#.to_string(),
            Language::Custom(custom) => custom.comment_begin.clone(),
        }
    }

    pub fn comment_end(&self) -> String {
        match self {
            Language::Rocq => "*)".to_string(),
            Language::Haskell => "-}".to_string(),
            Language::Racket => "|#".to_string(),
            Language::Rust => "*/".to_string(),
            Language::OCaml => "*)".to_string(),
            Language::Custom(custom) => custom.comment_end.clone(),
            Language::Python => r#"""""#.to_string(),
        }
    }

    pub fn variation_begin(&self, name: &str) -> String {
        format!(
            r"{}{} {}{}",
            self.comment_begin(),
            self.mutation_marker(),
            name,
            self.comment_end()
        )
    }

    pub fn variation_end(&self) -> String {
        format!(
            "{} {}{}",
            self.comment_begin(),
            self.mutation_marker(),
            self.comment_end()
        )
    }

    pub fn variant_header_begin(&self) -> String {
        format!(
            "{}{}{}",
            self.comment_begin(),
            self.mutation_marker(),
            self.mutation_marker()
        )
    }

    pub fn variant_header_end(&self) -> String {
        self.comment_end()
    }

    pub fn variant_body_begin(&self) -> String {
        format!("{}{}", self.comment_begin(), self.mutation_marker())
    }

    pub fn variant_body_end(&self) -> String {
        self.comment_end()
    }

    pub fn mutation_marker(&self) -> &str {
        match self {
            Language::Rocq
            | Language::Haskell
            | Language::Racket
            | Language::OCaml
            | Language::Python => "!",
            Language::Rust => "|",
            Language::Custom(custom_language) => custom_language.mutation_marker.as_str(),
        }
    }
}