darklua 0.1.0

Obfuscate Lua 5.1 scripts
Documentation
use crate::lua_generator::{LuaGenerator, ToLua};
use crate::nodes::Block;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FunctionName {
    name: String,
    field_names: Vec<String>,
    method: Option<String>,
}

impl FunctionName {
    pub fn new(name: String, field_names: Vec<String>, method: Option<String>) -> Self {
        Self {
            name,
            field_names,
            method,
        }
    }

    pub fn from_name<S: Into<String>>(name: S) -> Self {
        Self {
            name: name.into(),
            field_names: Vec::new(),
            method: None,
        }
    }

    pub fn with_fields(mut self, field_names: Vec<String>) -> Self {
        self.field_names = field_names;
        self
    }

    pub fn with_method(mut self, method: String) -> Self {
        self.method.replace(method);
        self
    }

    pub fn push_field(&mut self, field: String) {
        self.field_names.push(field);
    }

    pub fn remove_method(&mut self) -> Option<String> {
        self.method.take()
    }

    pub fn get_method(&mut self) -> &Option<String> {
        &self.method
    }

    pub fn get_name(&self) -> &String {
        &self.name
    }

    pub fn set_name(&mut self, name: String) {
        self.name = name;
    }
}

impl ToLua for FunctionName {
    fn to_lua(&self, generator: &mut LuaGenerator) {
        generator.push_str(&self.name);

        self.field_names.iter()
            .for_each(|field| {
                generator.push_char('.');
                generator.push_str(field);
            });

        if let Some(method_name) = &self.method {
            generator.push_char(':');
            generator.push_str(method_name);
        };
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FunctionStatement {
    name: FunctionName,
    block: Block,
    parameters: Vec<String>,
    is_variadic: bool,
}

impl FunctionStatement {
    pub fn new(name: FunctionName, block: Block, parameters: Vec<String>, is_variadic: bool) -> Self {
        Self {
            name,
            block,
            parameters,
            is_variadic,
        }
    }

    pub fn from_name<S: Into<String>>(name: S, block: Block) -> Self {
        Self {
            name: FunctionName::from_name(name),
            block,
            parameters: Vec::new(),
            is_variadic: false,
        }
    }

    pub fn append_parameter(mut self, parameter: String) -> Self {
        self.parameters.push(parameter);
        self
    }

    pub fn variadic(mut self) -> Self {
        self.is_variadic = true;
        self
    }

    pub fn get_block(&self) -> &Block {
        &self.block
    }

    pub fn mutate_block(&mut self) -> &mut Block {
        &mut self.block
    }

    pub fn mutate_function_name(&mut self) -> &mut FunctionName {
        &mut self.name
    }

    pub fn remove_method(&mut self) {
        if let Some(method_name) = self.name.remove_method() {
            self.name.push_field(method_name);
            self.parameters.insert(0, "self".to_owned());
        }
    }
}

impl ToLua for FunctionStatement {
    fn to_lua(&self, generator: &mut LuaGenerator) {
        generator.push_str("function");
        self.name.to_lua(generator);
        generator.push_char('(');

        generator.for_each_and_between(
            &self.parameters,
            |generator, parameter| generator.push_str(parameter),
            |generator| generator.push_char(','),
        );

        if self.is_variadic {
            if self.parameters.len() > 0 {
                generator.push_char(',');
            };
            generator.push_str("...");
        };

        generator.push_char(')');
        self.block.to_lua(generator);
        generator.push_str("end");
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn generate_() {
        let output = FunctionStatement::from_name("foo", Block::default())
            .to_lua_string();

        assert_eq!(output, "function foo()end");
    }
}