#![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);
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)?;
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);
}