forked from syndicate-lang/preserves
201 lines
7.0 KiB
Rust
201 lines
7.0 KiB
Rust
pub mod types;
|
|
pub mod names;
|
|
pub mod context;
|
|
pub mod parsers;
|
|
pub mod unparsers;
|
|
pub mod codegen;
|
|
|
|
use crate::*;
|
|
use crate::gen::schema::*;
|
|
use crate::syntax::block::Formatter;
|
|
use crate::syntax::block::constructors::*;
|
|
|
|
use glob::glob;
|
|
use preserves::value::BinarySource;
|
|
use preserves::value::IOBinarySource;
|
|
use preserves::value::Map;
|
|
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<String>;
|
|
|
|
#[derive(Debug)]
|
|
pub struct CompilerConfig {
|
|
pub bundle: Map<ModulePath, Schema>,
|
|
pub output_dir: PathBuf,
|
|
pub fully_qualified_module_prefix: String,
|
|
pub support_crate: String,
|
|
pub module_aliases: Map<ModulePath, 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(),
|
|
module_aliases: Map::new(),
|
|
}
|
|
}
|
|
|
|
pub fn load_schemas_and_bundles(&mut self, inputs: &Vec<PathBuf>) -> Result<(), Error> {
|
|
for i in inputs {
|
|
let mut f = File::open(&i)?;
|
|
let mut src = IOBinarySource::new(&mut f);
|
|
let mut reader = src.packed_iovalues();
|
|
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<String>) -> Result<Vec<PathBuf>, 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);
|
|
let module_name = output_path.file_stem().unwrap().to_str().unwrap().to_owned();
|
|
let module_name = names::render_modname(&module_name);
|
|
output_path.set_file_name(format!("{}.rs", module_name));
|
|
DirBuilder::new().recursive(true).create(output_path.parent().unwrap())?;
|
|
let mut m = context::ModuleContext::new(config);
|
|
|
|
let mut modes: Vec<context::ModuleContextMode> =
|
|
vec![context::ModuleContextMode::TargetAny];
|
|
|
|
match &v.embedded_type {
|
|
EmbeddedTypeName::False => {
|
|
m.define_type(item(seq!["pub type _Ptr = preserves::value::IOValue;"]));
|
|
m.define_type(item(seq!["pub type _Any = preserves::value::IOValue;"]));
|
|
}
|
|
EmbeddedTypeName::Ref(r) => {
|
|
modes.push(context::ModuleContextMode::TargetIOValue);
|
|
m.define_type(item(seq!["pub type _Dom = ", m.render_ref(&**r), ";"]));
|
|
m.define_type(item(seq!["pub type _Ptr = std::sync::Arc<_Dom>;"]));
|
|
m.define_type(item(seq!["pub type _Any = preserves::value::ArcValue<_Ptr>;"]));
|
|
}
|
|
}
|
|
|
|
let modes = modes; // rebind as non-mutable
|
|
|
|
for (n, d) in &v.definitions.0 {
|
|
m.define_type(item(types::render_definition_type(&m, n, &types::definition_type(d))));
|
|
m.define_type(item(seq!["impl preserves::value::Domain for ",
|
|
names::render_constructor(n), " {}"]));
|
|
for mode in &modes {
|
|
m.mode = *mode;
|
|
parsers::gen_definition_parser(&mut m, n, d);
|
|
unparsers::gen_definition_unparser(&mut m, n, d);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
let mut lines: Vec<String> = Vec::new();
|
|
|
|
lines.push("#![allow(unused_parens)]".to_owned());
|
|
lines.push("#![allow(unused_imports)]".to_owned());
|
|
lines.push("".to_owned());
|
|
lines.push("use std::convert::TryFrom;".to_owned());
|
|
lines.push("use preserves::value::Domain;".to_owned());
|
|
lines.push("use preserves::value::NestedValue;".to_owned());
|
|
lines.push(format!("use {}::support as _support;", &config.support_crate));
|
|
lines.push("".to_owned());
|
|
|
|
for mode in &modes {
|
|
m.mode = *mode;
|
|
lines.push(format!("mod {} {{", m.target_prefix()));
|
|
lines.push(" use super::_Any;".to_owned());
|
|
lines.push(format!(" use {}::support as _support;", &config.support_crate));
|
|
lines.push(" _support::lazy_static! {".to_owned());
|
|
for (value, name) in &m.literals {
|
|
let bs = preserves::value::PackedWriter::encode_iovalue(&value).unwrap();
|
|
lines.push(format!(
|
|
" pub static ref {}: {} = /* {:?} */ _support::decode_lit(&vec!{:?}).unwrap();",
|
|
name,
|
|
m.target(),
|
|
value,
|
|
bs));
|
|
}
|
|
lines.push(" }".to_owned());
|
|
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::<Result<Set<String>, Error>>()?
|
|
};
|
|
lines.insert(format!("pub mod {};", &module_name));
|
|
let mut f = File::create(mod_rs)?;
|
|
for line in lines {
|
|
write!(f, "{}\n", line)?;
|
|
}
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|