pub mod types; pub mod names; pub mod context; pub mod parsers; pub mod unparsers; pub mod codegen; use crate::gen::schema::*; use crate::syntax::block::Formatter; use crate::syntax::block::constructors::*; use glob::glob; use preserves::value::Map; use preserves::value::PackedReader; use preserves::value::Reader; use preserves::value::Set; use std::convert::TryFrom; use std::fs::DirBuilder; use std::fs::File; use std::io::BufRead; use std::io::BufReader; use std::io::Error; use std::io::ErrorKind; use std::io::Write; use std::path::PathBuf; pub type ModulePath = Vec; #[derive(Debug)] pub struct CompilerConfig { pub bundle: Map, pub output_dir: PathBuf, pub fully_qualified_module_prefix: String, pub support_crate: String, } impl CompilerConfig { pub fn new( output_dir: PathBuf, fully_qualified_module_prefix: String, ) -> Self { CompilerConfig { bundle: Map::new(), output_dir: output_dir, fully_qualified_module_prefix: fully_qualified_module_prefix, support_crate: "preserves_schema".to_owned(), } } pub fn load_schemas_and_bundles(&mut self, inputs: &Vec) -> Result<(), Error> { for i in inputs { let mut f = File::open(&i)?; let mut reader = PackedReader::decode_read(&mut f); let blob = reader.demand_next(false)?; if let Ok(s) = Schema::try_from(&blob) { let prefix = i.file_stem().ok_or_else( || Error::new(ErrorKind::InvalidData, format!("Bad schema file stem: {:?}", i)))? .to_str().ok_or_else( || Error::new(ErrorKind::InvalidData, format!("Invalid UTF-8 in schema file name: {:?}", i)))?; self.bundle.insert(vec![prefix.to_owned()], s); return Ok(()); } if let Ok(Bundle { modules }) = Bundle::try_from(&blob) { for (ModulePath(k), v) in modules.0 { self.bundle.insert(k, v); } return Ok(()); } return Err(Error::new(ErrorKind::InvalidData, format!("Invalid schema binary blob {:?}", i))); } Ok(()) } } pub fn expand_inputs(globs: &Vec) -> Result, Error> { let mut result = Vec::new(); for g in globs.iter() { for p in glob(g).map_err(|e| Error::new(ErrorKind::InvalidData, format!("{}", e)))? { result.push(p.map_err(glob::GlobError::into_error)?) } } Ok(result) } pub fn compile(config: &CompilerConfig) -> Result<(), std::io::Error> { for (k, v) in config.bundle.iter() { let mut output_path = config.output_dir.clone(); output_path.extend(k); output_path.set_extension("rs"); let module_name = output_path.file_stem().unwrap().to_str().unwrap().to_owned(); DirBuilder::new().recursive(true).create(output_path.parent().unwrap())?; let mut m = context::ModuleContext::new(config); // TODO: embedded type for (n, d) in &v.definitions.0 { m.define_type(item(types::render_definition_type(&m, n, &types::definition_type(d)))); parsers::gen_definition_parser(&mut m, n, d); unparsers::gen_definition_unparser(&mut m, n, d); } //--------------------------------------------------------------------------- let mut lines: Vec = Vec::new(); lines.push("#![allow(unused_parens)]".to_owned()); lines.push("".to_owned()); lines.push("use std::convert::TryFrom;".to_owned()); lines.push("use preserves::value::NestedValue;".to_owned()); lines.push(format!("use {}::support::*;", &config.support_crate)); lines.push("".to_owned()); lines.push("lazy_static! {".to_owned()); for (value, name) in m.literals { let bs = preserves::value::PackedWriter::encode(&value).unwrap(); lines.push(format!(" pub static ref {}: preserves::value::IOValue = /* {:?} */ preserves::value::packed::from_bytes(&vec!{:?}).unwrap();", name, value, bs)); } lines.push("}".to_owned()); lines.push("".to_owned()); for i in m.typedefs { lines.push(Formatter::to_string(i)); lines.push("".to_owned()); } for i in m.functiondefs { lines.push(Formatter::to_string(i)); lines.push("".to_owned()); } { let mut f = File::create(&output_path)?; for line in lines { write!(f, "{}\n", line)?; } } { let mut mod_rs = output_path.clone(); mod_rs.set_file_name("mod.rs"); let mut lines = if !mod_rs.exists() { Set::new() } else { BufReader::new(File::open(&mod_rs)?) .lines().collect::, Error>>()? }; lines.insert(format!("pub mod {};", &module_name)); let mut f = File::create(mod_rs)?; for line in lines { write!(f, "{}\n", line)?; } } } Ok(()) }