genesys 0.1.2

Component format & build code generation, no more repetitions!
Documentation
#![allow(dead_code, unused_variables, unused_mut)]

#[macro_use]
extern crate pest_derive;

mod codegen;

use std::collections::HashMap;
use std::path::PathBuf;

use pest::Parser;

pub fn generate(path: &str, to: PathBuf) -> std::io::Result<()> {
    let raw = std::fs::read(path)?;
    let data = String::from_utf8_lossy(&raw);

    let ast = parse_genesys_file(&data);
    if let Ok(ast) = ast {
        codegen::write(ast, to)?;
    }

    Ok(())
}

pub fn print(path: &str) -> std::io::Result<()> {
    let raw = std::fs::read(path)?;
    let data = String::from_utf8_lossy(&raw);

    let result = parse_genesys_file(&data);
    //println!("{:#?}", result);

    if let GenesysValue::File(tokens) = result.unwrap() {
        let s = codegen::parse_file_ast(tokens);
        println!("{}", s);
    }

    Ok(())
}

#[derive(Debug)]
pub enum GenesysValue<'a> {
    GlobUse(&'a str, Vec<GenesysValue<'a>>),
    GlobDerive(Vec<GenesysValue<'a>>),
    LocalUse(&'a str, Vec<GenesysValue<'a>>),
    LocalDerive(Vec<GenesysValue<'a>>),
    SingleComponent(&'a str),
    TupleComponent(&'a str, Vec<&'a str>),
    NamedComponent(&'a str, HashMap<&'a str, &'a str>),
    String(&'a str),
    File(Vec<GenesysValue<'a>>),
    Module(&'a str, Vec<GenesysValue<'a>>),
    Empty,
}
#[derive(Parser)]
#[grammar = "genesys.pest"]
pub struct GenesysParser;

fn parse_genesys_file(data: &str) -> Result<GenesysValue, pest::error::Error<Rule>> {
    // ...

    use pest::iterators::Pair;

    fn parse_value(pair: Pair<Rule>) -> GenesysValue {
        match pair.as_rule() {
            Rule::glob_use => {
                let mut uses = Vec::new();
                for pair in pair.into_inner() {
                    uses.push(parse_value(pair));
                }
                GenesysValue::GlobUse("", uses)
            }
            Rule::use_bracket => {
                let mut inner = pair.into_inner();
                let name = inner.next().unwrap().as_str();
                let uses = inner.map(|e| parse_value(e)).collect();

                GenesysValue::GlobUse(name, uses)
            }
            Rule::glob_derive => {
                let derives = pair
                    .into_inner()
                    .map(|e| GenesysValue::String(e.as_str()))
                    .collect();

                GenesysValue::GlobDerive(derives)
            }
            Rule::module => {
                let mut inner = pair.into_inner();
                let name = inner.next().unwrap().as_str();
                let children = inner.map(|e| parse_value(e)).collect();

                GenesysValue::Module(name, children)
            }
            Rule::local_use => {
                let mut inner = pair.into_inner();
                let name = inner.next().unwrap().as_str();
                let uses = inner.map(|e| parse_value(e)).collect();

                GenesysValue::LocalUse(name, uses)
            }
            Rule::local_derive => {
                let derives = pair
                    .into_inner()
                    .map(|e| GenesysValue::String(e.as_str()))
                    .collect();

                GenesysValue::LocalDerive(derives)
            }
            Rule::single_component => GenesysValue::SingleComponent(pair.as_str()),
            Rule::tuple_component => {
                let mut inner = pair.into_inner();
                let name = inner.next().unwrap().as_str();
                let fields = inner.map(|e| e.as_str()).collect();

                GenesysValue::TupleComponent(name, fields)
            }
            Rule::named_component => {
                let mut inner = pair.into_inner();
                let name = inner.next().unwrap().as_str();

                let mut hm = HashMap::new();
                for pair in inner {
                    let mut inner = pair.into_inner();
                    let field = inner.next().unwrap().as_str();
                    let value = inner.next().unwrap().as_str();
                    hm.insert(field, value);
                }

                GenesysValue::NamedComponent(name, hm)
            }
            Rule::types => GenesysValue::Empty,
            Rule::STRING => GenesysValue::String(pair.as_str()),
            Rule::EOI => GenesysValue::Empty,
            Rule::use_value
            | Rule::COMMENT
            | Rule::comment_block
            | Rule::comment_line
            | Rule::pair
            | Rule::components
            | Rule::cname
            | Rule::ints
            | Rule::uints
            | Rule::floats
            | Rule::strings
            | Rule::file
            | Rule::WHITESPACE => unreachable!(),
        }
    }

    let mut ast = Vec::new();
    let mut file = GenesysParser::parse(Rule::file, &data)?;
    //println!("{:#?}", file);

    for pair in file {
        ast.push(parse_value(pair))
    }

    Ok(GenesysValue::File(ast))
}

#[test]
fn parse() {
    let data = std::fs::read_to_string("examples/components.pest").unwrap();
    let result = parse_genesys_file(&data);
    assert!(result.is_ok(), "{}", true);
}

#[test]
fn parse_tuple_struct() {
    let result = GenesysParser::parse(Rule::tuple_component, "MyTupleComponent str, str");
    assert!(result.is_ok(), "{}", true);
}