rustaveli 0.1.0

A library to generate random c programs
Documentation
use crate::ctype::*;
use crate::random_string::*;
use crate::statics::*;
use rand::prelude::*;

#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub(crate) struct CVariable {
    pub(crate) type_: CType,
    pub(crate) name: String,
    pub(crate) value: String,
}

impl CVariable {
    pub fn new(type_: Option<String>, name: Option<&str>, value: Option<&str>) -> Self {
        let mut rt = Self::default();

        let mut rng = thread_rng();

        rt.type_ = CType::new(
            type_.unwrap_or(
                AVAILABLE_TYPES
                    .iter()
                    .map(|x| x.key().clone())
                    .collect::<Vec<_>>()[rng.gen_range(0..AVAILABLE_TYPES.len()) as usize]
                    .clone(),
            ),
        );

        rt.name = name
            .unwrap_or(&RandomString::new(None, None).value)
            .to_string();
        rt.value = value.unwrap_or(&rt.type_.random_value()).to_string();

        return rt;
    }

    pub fn generate_defenition(&self) -> String {
        return format!(
            "volatile {} {} = {};",
            self.type_.to_string(),
            self.name,
            self.value
        );
    }

    pub fn apply_operation(&self, rhs: &Self, op: Option<String>) -> String {
        if !PRIMITIVE_TYPES.contains(&self.type_.to_string()) && op.is_some() {
            eprintln!(
                "[WARN] Structs can only have random operators applied. Returning an empty string"
            );
            return String::new();
        }

        if !PRIMITIVE_TYPES.contains(&self.type_.to_string()) {
            if self.type_.to_string() != rhs.type_.to_string() {
                eprintln!("[WARN] Struct types don't match. Returning an empty string");
                return String::new();
            }

            return AVAILABLE_TYPES
                .get(&self.type_.to_string())
                .unwrap()
                .self_
                .clone()
                .unwrap()
                .apply_random_instruction_to_each_field(
                    &AVAILABLE_TYPES
                        .get(&rhs.type_.to_string())
                        .unwrap()
                        .self_
                        .clone()
                        .unwrap(),
                    &self.name,
                    &rhs.name,
                );
        }

        let mut op = op.unwrap_or_default();

        if op.is_empty() {
            let mut n = 0;

            let self_instructions = &AVAILABLE_TYPES
                .get(&self.type_.to_string())
                .unwrap()
                .instructions;
            let rhs_instructions = &AVAILABLE_TYPES
                .get(&rhs.type_.to_string())
                .unwrap()
                .instructions;

            let mut rng = thread_rng();

            while !self_instructions.contains(&op) || !rhs_instructions.contains(&op) {
                op = self_instructions[rng.gen_range(0..self_instructions.len()) as usize].clone();

                n += 1;

                if n > 10 {
                    eprintln!("[WARN] Operation finding iteration maximum reached. Returning an empty string");
                    return String::new();
                }
            }
        }

        match op.as_str() {
            "append" | "dup" => {
                return AVAILABLE_TYPES
                    .get("char*")
                    .unwrap()
                    .instruction_function
                    .unwrap()(self.name.clone(), Some(rhs.name.clone()), op);
            }

            _ => {
                return format!(
                    "({}) ({} {} {})",
                    self.type_.to_string(),
                    self.name,
                    op,
                    rhs.name
                )
            }
        }
    }
}