genesys 0.1.2

Component format & build code generation, no more repetitions!
Documentation
use crate::GenesysValue;
use std::io::Write;
use std::path::PathBuf;

pub fn write(ast: GenesysValue, to: PathBuf) -> Result<(), std::io::Error> {
    let mut f = std::fs::File::create(to);
    if let Ok(fd) = f {
        let mut bufwriter = std::io::BufWriter::new(fd);

        if let GenesysValue::File(tokens) = ast {
            let s = parse_file_ast(tokens);
            bufwriter.write(s.as_bytes())?;
        }
    }

    Ok(())
}

pub fn parse_file_ast(ast: Vec<GenesysValue>) -> String {
    let mut data = String::new();

    let mut global_use = None;
    let mut global_derive = None;

    for token in ast.iter() {
        match token {
            GenesysValue::GlobUse(name, vec) => {
                global_use = Some(parse_token(&None, &None, token, 0));
            }
            GenesysValue::GlobDerive(derive) => {
                global_derive = Some(parse_token(&None, &None, token, 0));
            }
            _ => data += &parse_token(&global_use, &global_derive, token, 0),
        }
    }

    //data = global_derive + &data;
    data = global_use.unwrap_or(String::from("")) + &data;

    data
}

pub fn parse_token(
    global_use: &Option<String>,
    global_derive: &Option<String>,
    token: &GenesysValue,
    level: u8,
) -> String {
    let mut data = String::new();

    match token {
        GenesysValue::GlobUse(name, vec) => {
            if level == 1 {
                data += &format!("use {}{{\n", name);
            } else if level > 1 {
                data += &format!("{}{{\n", name);
            }

            for e in vec {
                match e {
                    GenesysValue::String(s) => {
                        if level == 0 {
                            data += &format!("use {};\n", s);
                        } else {
                            data += &format!("{},\n", s)
                        }
                    }
                    _ => {
                        data += &parse_token(global_use, global_derive, e, level + 1);
                    }
                }
            }

            if level > 0 {
                data += &format!("}},\n");
            } else {
                //data += &format!("}}\n");
            }
        }
        GenesysValue::GlobDerive(v) => {
            data += &format!(
                "#[derive({})]\n",
                v.iter()
                    .filter_map(|e| {
                        if let GenesysValue::String(s) = e {
                            return Some(*s);
                        }

                        None
                    })
                    .collect::<Vec<_>>()
                    .join(",")
            );
        }
        GenesysValue::LocalUse(name, vec) => {
            if level != 0 {
                data += &format!("{}{{\n", name);
            }

            for e in vec {
                match e {
                    GenesysValue::String(s) => {
                        if level == 0 {
                            data += &format!("use {};\n", s);
                        } else {
                            data += &format!("{},\n", s)
                        }
                    }
                    _ => {
                        data += &parse_token(global_use, global_derive, e, level + 1);
                    }
                }
            }

            if level > 0 {
                data += &format!("}},\n");
            } else {
                data += &format!("}}\n");
            }
        }
        GenesysValue::LocalDerive(v) => {
            data += &format!(
                "#[derive({})]\n",
                v.iter()
                    .filter_map(|e| {
                        if let GenesysValue::String(s) = e {
                            return Some(*s);
                        }

                        None
                    })
                    .collect::<Vec<_>>()
                    .join(",")
            );
        }
        GenesysValue::SingleComponent(n) => {
            if let Some(derive) = global_derive {
                data += derive;
            }

            data += &format!("pub struct {};\n", n);
        }
        GenesysValue::TupleComponent(n, v) => {
            if let Some(derive) = global_derive {
                data += derive;
            }

            data += &format!("pub struct {}({});\n", n, v.iter().map(|e| format!("pub {}", e)).collect::<Vec<_>>().join(","));
        }
        GenesysValue::NamedComponent(n, hm) => {
            if let Some(derive) = global_derive {
                data += derive;
            }

            data += &format!(
                "pub struct {} {{\n{}\n}}\n",
                n,
                hm.iter()
                    .map(|(k, v)| format!("pub {}: {}", k, v.replace("str", "String")))
                    .collect::<Vec<_>>()
                    .join(",\n")
            );
        }
        GenesysValue::Module(name, children) => {
            data += &format!("pub mod {} {{\n", name);

            if let Some(guse) = global_use {
                data += guse;
            }

            let mut derive = None;
            for child in children.iter() {
                if let GenesysValue::LocalDerive(local_derive) = &child {
                    derive = Some(parse_token(global_use, &None, child, level + 1));
                } else if derive.is_some() {
                    data += &format!("{}", parse_token(global_use, &derive, child, level + 1));
                } else {
                    data += &format!(
                        "{}",
                        parse_token(global_use, global_derive, child, level + 1)
                    );
                }
            }

            data += "}\n";
        }
        GenesysValue::String(v) => {}
        GenesysValue::File(v) => {}
        GenesysValue::Empty => {}
    }

    data
}