From 4144a90b9d8a8aceb638f480487472b0127d989f Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Mon, 28 Jun 2021 16:35:45 +0200 Subject: [PATCH] Initial commit (several days' worth) --- implementations/rust/Cargo.toml | 1 + .../rust/preserves-schema/Cargo.toml | 14 + .../rust/preserves-schema/Makefile | 6 + .../src/bin/preserves-schema-rs.rs | 66 +++ .../preserves-schema/src/compiler/context.rs | 71 +++ .../rust/preserves-schema/src/compiler/mod.rs | 75 +++ .../preserves-schema/src/compiler/names.rs | 17 + .../preserves-schema/src/compiler/parsers.rs | 276 +++++++++ .../preserves-schema/src/compiler/types.rs | 175 ++++++ .../rust/preserves-schema/src/lib.rs | 43 ++ .../rust/preserves-schema/src/metaschema.rs | 532 ++++++++++++++++++ .../rust/preserves-schema/src/syntax/block.rs | 274 +++++++++ .../rust/preserves-schema/src/syntax/mod.rs | 1 + .../rust/preserves/src/value/mod.rs | 1 + .../rust/preserves/src/value/repr.rs | 16 + 15 files changed, 1568 insertions(+) create mode 100644 implementations/rust/preserves-schema/Cargo.toml create mode 100644 implementations/rust/preserves-schema/Makefile create mode 100644 implementations/rust/preserves-schema/src/bin/preserves-schema-rs.rs create mode 100644 implementations/rust/preserves-schema/src/compiler/context.rs create mode 100644 implementations/rust/preserves-schema/src/compiler/mod.rs create mode 100644 implementations/rust/preserves-schema/src/compiler/names.rs create mode 100644 implementations/rust/preserves-schema/src/compiler/parsers.rs create mode 100644 implementations/rust/preserves-schema/src/compiler/types.rs create mode 100644 implementations/rust/preserves-schema/src/lib.rs create mode 100644 implementations/rust/preserves-schema/src/metaschema.rs create mode 100644 implementations/rust/preserves-schema/src/syntax/block.rs create mode 100644 implementations/rust/preserves-schema/src/syntax/mod.rs diff --git a/implementations/rust/Cargo.toml b/implementations/rust/Cargo.toml index fd9b7d2..433e87a 100644 --- a/implementations/rust/Cargo.toml +++ b/implementations/rust/Cargo.toml @@ -1,4 +1,5 @@ [workspace] members = [ "preserves", + "preserves-schema", ] diff --git a/implementations/rust/preserves-schema/Cargo.toml b/implementations/rust/preserves-schema/Cargo.toml new file mode 100644 index 0000000..c9193c5 --- /dev/null +++ b/implementations/rust/preserves-schema/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "preserves-schema" +version = "0.1.0" +edition = "2018" + +[dependencies] +preserves = { path = "../preserves" } + +structopt = "0.3.14" +glob = "0.3.0" + +convert_case = "0.4.0" + +lazy_static = "1.4.0" diff --git a/implementations/rust/preserves-schema/Makefile b/implementations/rust/preserves-schema/Makefile new file mode 100644 index 0000000..83d832c --- /dev/null +++ b/implementations/rust/preserves-schema/Makefile @@ -0,0 +1,6 @@ +all: + @echo please use cargo + +regenerate: + cargo run -- -o $(CURDIR)/src --prefix schema ../../../schema/schema.bin > src/metaschema.rs.tmp + mv src/metaschema.rs.tmp src/metaschema.rs diff --git a/implementations/rust/preserves-schema/src/bin/preserves-schema-rs.rs b/implementations/rust/preserves-schema/src/bin/preserves-schema-rs.rs new file mode 100644 index 0000000..0b8b979 --- /dev/null +++ b/implementations/rust/preserves-schema/src/bin/preserves-schema-rs.rs @@ -0,0 +1,66 @@ +use std::path::PathBuf; +use std::fs::File; +use preserves::value::packed::PackedReader; +use preserves::value::{NestedValue, Reader}; +use structopt::StructOpt; +use glob::glob; + +use preserves_schema::compiler::{CompilerConfig, compile}; + +#[derive(Clone, StructOpt, Debug)] +struct CommandLine { + #[structopt(short, long)] + output_dir: PathBuf, + + #[structopt(long)] + prefix: Option, + + input_glob: Vec, +} + +fn inputs(globs: &Vec) -> Vec { + let mut result = Vec::new(); + for g in globs.iter() { + match glob(g) { + Ok(paths) => + for p in paths { + match p { + Ok(s) => result.push(s), + Err(e) => println!("warning: {:?}", e), + } + } + Err(e) => println!("warning: {:?}", e), + } + } + result +} + +fn main() -> Result<(), std::io::Error> { + let args = CommandLine::from_args(); + + let prefix = match &args.prefix { + Some(s) => s.split(".").map(str::to_string).collect(), + None => vec![], + }; + + let mut config = CompilerConfig::new(args.output_dir); + + for i in inputs(&args.input_glob) { + let mut f = File::open(&i)?; + let mut reader = PackedReader::decode_read(&mut f); + let schema = reader.demand_next(false)?; + if let Some(s) = schema.value().as_simple_record("schema", Some(1)) { + config.bundle.insert(prefix.clone(), s[0].clone()); + } else if let Some(b) = schema.value().as_simple_record("bundle", Some(1)) { + for (k, v) in b[0].value().to_dictionary()? { + let mut name = prefix.clone(); + for p in k.value().to_sequence()? { + name.push(p.value().to_string()?.to_owned()); + } + config.bundle.insert(name, v.clone()); + } + } + } + + compile(&config) +} diff --git a/implementations/rust/preserves-schema/src/compiler/context.rs b/implementations/rust/preserves-schema/src/compiler/context.rs new file mode 100644 index 0000000..54a085f --- /dev/null +++ b/implementations/rust/preserves-schema/src/compiler/context.rs @@ -0,0 +1,71 @@ +use preserves::value::{Map, IOValue}; + +use crate::syntax::block::Item; + +use super::types; + +pub struct ModuleContext { + pub literals: Map, + pub typedefs: Vec, + pub functiondefs: Vec, +} + +pub struct FunctionContext<'a> { + pub m: &'a mut ModuleContext, + pub temp_counter: usize, + pub temps: Map>, + pub captures: Vec, +} + +pub struct Capture { + pub field_name: String, + pub source_expr: String, +} + +impl ModuleContext { + pub fn new() -> Self { + ModuleContext { + literals: Map::new(), + typedefs: Vec::new(), + functiondefs: Vec::new(), + } + } + + pub fn define_literal(&mut self, v: &IOValue) -> String { + let next_id = format!("LIT{}", self.literals.len()); + "&*".to_owned() + self.literals.entry(v.clone()).or_insert(next_id) + } + + pub fn define_type(&mut self, i: Item) { + self.typedefs.push(i) + } + + pub fn define_function Item>(&mut self, f: F) { + let i = f(FunctionContext::new(self)); + self.functiondefs.push(i) + } +} + +impl<'a> FunctionContext<'a> { + pub fn new(m: &'a mut ModuleContext) -> Self { + FunctionContext { + m: m, + temp_counter: 0, + temps: Map::new(), + captures: Vec::new(), + } + } + + pub fn capture(&mut self, field_name: &str, source_expr: &str) { + self.captures.push(Capture { + field_name: field_name.to_owned(), + source_expr: source_expr.to_owned(), + }) + } + + pub fn gentempname(&mut self) -> String { + let i = self.temp_counter; + self.temp_counter += 1; + format!("_tmp{}", i) + } +} diff --git a/implementations/rust/preserves-schema/src/compiler/mod.rs b/implementations/rust/preserves-schema/src/compiler/mod.rs new file mode 100644 index 0000000..697450e --- /dev/null +++ b/implementations/rust/preserves-schema/src/compiler/mod.rs @@ -0,0 +1,75 @@ +pub mod types; +pub mod names; +pub mod context; +pub mod parsers; + +use std::path::PathBuf; +use preserves::value::{Map, IOValue, NestedValue, Value}; + +use crate::syntax::block::constructors::*; + +pub type ModulePath = Vec; + +pub type Schema = IOValue; + +#[derive(Debug)] +pub struct CompilerConfig { + pub bundle: Map, + pub output_dir: PathBuf, +} + +impl CompilerConfig { + pub fn new(output_dir: PathBuf) -> Self { + CompilerConfig { + bundle: Map::new(), + output_dir: output_dir, + } + } +} + +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 mut m = context::ModuleContext::new(); + + // println!("\n{:?}", &output_path); + + // TODO: embedded type + + let definitions = v.value().to_dictionary()?.get(&Value::symbol("definitions").wrap()) + .unwrap().value().to_dictionary()?; + + for (n, d) in definitions.iter() { + m.define_type(item(types::render_definition_type( + n.value().to_symbol()?, + &types::definition_type(d)?))); + + parsers::gen_definition_parser(&mut m, n.value().to_symbol()?, &d); + } + + //--------------------------------------------------------------------------- + + println!("#![allow(unused_parens)]"); + println!(); + println!("use std::convert::TryFrom;"); + println!("use preserves::value::{{NestedValue, Reader}};"); + println!("use lazy_static::lazy_static;"); + println!(); + + println!("lazy_static! {{"); + for (value, name) in m.literals { + let bs = preserves::value::PackedWriter::encode(&value).unwrap(); + println!(" pub static ref {}: preserves::value::IOValue = /* {:?} */ preserves::value::PackedReader::decode_bytes(&vec!{:?}).demand_next(false).unwrap();", + name, + value, + bs); + } + println!("}}\n"); + + for i in m.typedefs { println!("{:?}\n", i); } + for i in m.functiondefs { println!("{:?}\n", i); } + } + Ok(()) +} diff --git a/implementations/rust/preserves-schema/src/compiler/names.rs b/implementations/rust/preserves-schema/src/compiler/names.rs new file mode 100644 index 0000000..16c7e00 --- /dev/null +++ b/implementations/rust/preserves-schema/src/compiler/names.rs @@ -0,0 +1,17 @@ +use crate::syntax::block::Emittable; +use crate::syntax::block::constructors::*; +use convert_case::{Case, Casing}; + +pub fn render_ref(pieces: Vec) -> impl Emittable { + let mut items = Vec::new(); + for p in pieces { items.push(item(p)); } + name(items) +} + +pub fn render_constructor(n: &str) -> String { + n.to_case(Case::UpperCamel) +} + +pub fn render_fieldname(n: &str) -> String { + n.to_case(Case::Snake) +} diff --git a/implementations/rust/preserves-schema/src/compiler/parsers.rs b/implementations/rust/preserves-schema/src/compiler/parsers.rs new file mode 100644 index 0000000..5814dd2 --- /dev/null +++ b/implementations/rust/preserves-schema/src/compiler/parsers.rs @@ -0,0 +1,276 @@ +use crate::*; +use crate::syntax::block::Item; +use crate::syntax::block::constructors::*; +use preserves::value::{IOValue, NestedValue}; +use super::names; +use super::types::*; +use super::context::{ModuleContext, FunctionContext}; + +pub fn gen_definition_parser(m: &mut ModuleContext, n: &str, d: &IOValue) { + m.define_function( + |mut ctxt| { + let mut body = Vec::new(); + + if let Some(fs) = d.value().as_simple_record("or", Some(1)) { + for e in fs[0].value().to_sequence().unwrap() { + let e = e.value().to_sequence().unwrap(); + let name = e[0].value().to_string().unwrap(); + let pat = &e[1]; + let fname = seq!["_parse_", names::render_fieldname(n), "_", names::render_fieldname(name)]; + let ctorname = item(name![names::render_constructor(n), names::render_constructor(name)]); + ctxt.m.define_function( + |mut ctxt| { + let mut body = Vec::new(); + let dest = pattern_parser(&mut ctxt, pat, "value", None, &mut body); + let dest = dest.as_ref().map(String::as_str); + construct(&ctxt, ctorname, &TDefinition::Simple(simple_type(pat).unwrap()), dest, &mut body); + item(seq!["fn ", fname.clone(), "(value: &preserves::value::IOValue) -> ", + "std::result::Result<", names::render_constructor(n), ", ()> ", + block(body)]) + }); + body.push(item(seq!["if let Ok(r) = ", fname, "(value) { return Ok(r); }"])); + } + body.push(item(seq!["Err(())"])); + } else if let Some(fs) = d.value().as_simple_record("and", Some(1)) { + for e in fs[0].value().to_sequence().unwrap() { + pattern_parser(&mut ctxt, e, "value", None, &mut body); + } + construct(&ctxt, item(names::render_constructor(n)), &definition_type(d).unwrap(), None, &mut body); + } else { + let dest = pattern_parser(&mut ctxt, d, "value", None, &mut body); + let dest = dest.as_ref().map(String::as_str); + construct(&ctxt, item(names::render_constructor(n)), &definition_type(d).unwrap(), dest, &mut body); + } + + item(seq!["impl std::convert::TryFrom", anglebrackets!["&preserves::value::IOValue"], " for ", + names::render_constructor(n), " ", block![ + seq!["type Error = ();"], + seq!["fn try_from(value: &preserves::value::IOValue) -> ", + "std::result::Result ", + block(body)]]]) + }); +} + +fn construct( + ctxt: &FunctionContext, + ctorname: Item, + ty: &TDefinition, + dest: Option<&str>, + body: &mut Vec, +) { + match ty { + TDefinition::Simple(TSimple::Field(TField::Unit)) => + body.push(item(seq!["Ok(", ctorname, ")"])), + TDefinition::Simple(TSimple::Field(fieldty)) => + body.push(item(seq!["Ok(", ctorname, parens![store_wrap(fieldty, dest.unwrap())], ")"])), + _ => + body.push(item(seq!["Ok(", ctorname, " ", braces( + ctxt.captures.iter().map( + |c| item(seq![c.field_name.clone(), ": ", c.source_expr.clone()])).collect()), + ")"])), + } +} + +fn store_wrap(ty: &TField, expr: &str) -> String { + match ty { + TField::Unit + | TField::Array(_) + | TField::Set(_) + | TField::Map(_, _) => expr.to_owned(), + TField::Ref(_) => format!("std::boxed::Box::new({})", expr), + TField::Base(_) => format!("{}.clone()", expr), + } +} + +fn item_store_wrap(ty: &TField, expr: &str) -> String { + match ty { + TField::Unit + | TField::Array(_) + | TField::Set(_) + | TField::Map(_, _) + | TField::Ref(_) => expr.to_owned(), + TField::Base(_) => format!("{}.clone()", expr), + } +} + +fn push_let(body: &mut Vec, name: &str, expr: Item) { + body.push(item(seq!["let ", name.to_owned(), " = ", expr, ";"])) +} + +fn push_let_mut(body: &mut Vec, name: &str, expr: Item) { + body.push(item(seq!["let mut ", name.to_owned(), " = ", expr, ";"])) +} + +fn simple_pattern_parser( + ctxt: &mut FunctionContext, + p: &IOValue, + src: &str, + sequence_base: Option, + body: &mut Vec, +) -> Option { + let dest = ctxt.gentempname(); + if p.value().as_symbol() == Some(&"any".to_owned()) { + push_let(body, &dest, item(src.to_owned())); + Some(dest) + } else if let Some(fs) = p.value().as_simple_record("atom", Some(1)) { + match fs[0].value().as_symbol().unwrap().as_str() { + "Boolean" => push_let(body, &dest, item(seq![src.to_owned(), ".value().to_boolean().map_err(|_| ())?"])), + "Float" => push_let(body, &dest, item(seq![src.to_owned(), ".value().to_float().map_err(|_| ())?"])), + "Double" => push_let(body, &dest, item(seq![src.to_owned(), ".value().to_double().map_err(|_| ())?"])), + "SignedInteger" => push_let(body, &dest, item(seq![src.to_owned(), ".value().to_signedinteger().map_err(|_| ())?"])), + "String" => push_let(body, &dest, item(seq![src.to_owned(), ".value().to_string().map_err(|_| ())?"])), + "ByteString" => push_let(body, &dest, item(seq![src.to_owned(), ".value().to_bytestring().map_err(|_| ())?"])), + "Symbol" => push_let(body, &dest, item(seq![src.to_owned(), ".value().to_symbol().map_err(|_| ())?"])), + _ => panic!("Unexpected AtomKind"), + } + Some(dest) + } else if let Some(_) = p.value().as_simple_record("embedded", Some(1)) { + push_let(body, &dest, item(seq![src.to_owned(), ".value().to_embedded().map_err(|_| ())?"])); + Some(dest) + } else if let Some(fs) = p.value().as_simple_record("lit", Some(1)) { + body.push(item(seq!["if ", src.to_owned(), " != ", ctxt.m.define_literal(&fs[0]), + " { return Err(()); }"])); + push_let(body, &dest, item("()")); + Some(dest) + } else if let Some(fs) = p.value().as_simple_record("seqof", Some(1)) { + let (src, n) = sequenceify(ctxt, src, sequence_base, body); + let tmp = ctxt.gentempname(); + let mut inner = Vec::new(); + let item_dest = simple_pattern_parser(ctxt, &fs[0], &tmp, None, &mut inner); + inner.push(item(seq![ + dest.to_owned(), ".push(", + item_store_wrap(&field_type(&fs[0]).unwrap().unwrap(), &item_dest.unwrap()), ");"])); + push_let_mut(body, &dest, item("std::vec::Vec::new()")); + body.push(item(seq!["for ", tmp.to_owned(), + " in &", src.to_owned(), brackets![seq![n.to_string() , ".."]], + " ", block(inner)])); + Some(dest) + } else if let Some(fs) = p.value().as_simple_record("setof", Some(1)) { + let tmp = ctxt.gentempname(); + let mut inner = Vec::new(); + let item_dest = simple_pattern_parser(ctxt, &fs[0], &tmp, None, &mut inner); + inner.push(item(seq![ + dest.to_owned(), ".insert(", + item_store_wrap(&field_type(&fs[0]).unwrap().unwrap(), &item_dest.unwrap()), ");"])); + push_let_mut(body, &dest, item("preserves::value::Set::new()")); + body.push(item(seq!["for ", tmp.to_owned(), + " in ", src.to_owned(), ".value().to_set().map_err(|_| ())?", + " ", block(inner)])); + Some(dest) + } else if let Some(fs) = p.value().as_simple_record("dictof", Some(2)) { + let tmp_key = ctxt.gentempname(); + let tmp_value = ctxt.gentempname(); + let mut inner = Vec::new(); + let key_dest = simple_pattern_parser(ctxt, &fs[0], &tmp_key, None, &mut inner); + let value_dest = simple_pattern_parser(ctxt, &fs[1], &tmp_value, None, &mut inner); + inner.push(item(seq![ + dest.to_owned(), ".insert(", + item_store_wrap(&field_type(&fs[0]).unwrap().unwrap(), &key_dest.unwrap()), ", ", + item_store_wrap(&field_type(&fs[1]).unwrap().unwrap(), &value_dest.unwrap()), ");"])); + push_let_mut(body, &dest, item("preserves::value::Map::new()")); + body.push(item(seq!["for (", tmp_key.to_owned(), ", ", tmp_value.to_owned(), ")", + " in ", src.to_owned(), ".value().to_dictionary().map_err(|_| ())?", + " ", block(inner)])); + Some(dest) + } else if let Some(fs) = p.value().as_simple_record("ref", Some(2)) { + let mut n: Vec = fs[0].value().to_sequence().unwrap() + .iter().map(|s| s.value().to_symbol().unwrap().to_owned()).collect(); + use convert_case::{Case, Casing}; + n.push(fs[1].value().to_symbol().unwrap().to_case(Case::UpperCamel)); + let tf = name![names::render_ref(n), "try_from"]; + push_let(body, &dest, item(seq![tf, + parens![src.to_owned()], + "?"])); + Some(dest) + } else { + None + } +} + +fn sequenceify( + ctxt: &mut FunctionContext, + src: &str, + sequence_base: Option, + body: &mut Vec, +) -> (String, usize) { + match sequence_base { + Some(n) => (src.to_owned(), n), + None => { + let tmp = ctxt.gentempname(); + push_let(body, &tmp, item(seq![src.to_owned(), ".value().to_sequence().map_err(|_| ())?"])); + (tmp, 0) + } + } +} + +fn fixed_sequence_parser( + ctxt: &mut FunctionContext, + base: usize, + ps: &[IOValue], + src: &str, + body: &mut Vec, +) { + let mut i = base; + body.push(item(seq!["if ", src.to_owned(), ".len() - ", base.to_string(), " < ", + ps.len().to_string(), " { return Err(()); }"])); + for p in ps { + pattern_parser(ctxt, p, &format!("(&{}[{}])", src, i), None, body); + i += 1; + } +} + +fn pattern_parser( + ctxt: &mut FunctionContext, + p: &IOValue, + src: &str, + sequence_base: Option, + body: &mut Vec, +) -> Option { + match simple_pattern_parser(ctxt, p, src, sequence_base, body) { + Some(dest) => Some(dest), + None => { + // Compound + let r = p.value().as_record(None).unwrap(); + match r.label().value().as_symbol().unwrap().as_ref() { + "named" => { + let dest = simple_pattern_parser(ctxt, &r.fields()[1], src, sequence_base, body).unwrap(); + let capture_expr = store_wrap(&field_type(&r.fields()[1]).unwrap().unwrap(), &dest); + ctxt.capture(&names::render_fieldname(r.fields()[0].value().as_symbol().unwrap()), + &capture_expr); + Some(dest) + } + "rec" => { + let rtmp = ctxt.gentempname(); + push_let(body, &rtmp, item(seq![src.to_owned(), ".value().to_record(None).map_err(|_| ())?"])); + pattern_parser(ctxt, &r.fields()[0], &format!("{}.label()", rtmp), None, body); + pattern_parser(ctxt, &r.fields()[1], &format!("{}.fields()", rtmp), Some(0), body); + None + } + "tuple" => { + let (src, n) = sequenceify(ctxt, src, sequence_base, body); + fixed_sequence_parser(ctxt, n, r.fields()[0].value().to_sequence().unwrap(), &src, body); + None + } + "tuplePrefix" => { + let (src, n) = sequenceify(ctxt, src, sequence_base, body); + let fixed = r.fields()[0].value().to_sequence().unwrap(); + fixed_sequence_parser(ctxt, n, fixed, &src, body); + pattern_parser(ctxt, &r.fields()[1], &src, Some(n + fixed.len()), body) + } + "dict" => { + let dtmp = ctxt.gentempname(); + push_let(body, &dtmp, item(seq![src.to_owned(), ".value().to_dictionary().map_err(|_| ())?"])); + for (key_lit, value_pat) in r.fields()[0].value().to_dictionary().unwrap() { + let vtmp = ctxt.gentempname(); + push_let(body, &vtmp, item(seq![ + dtmp.to_owned(), ".get", parens![ctxt.m.define_literal(key_lit)], + ".ok_or(())?"])); + pattern_parser(ctxt, value_pat, &vtmp, None, body); + } + None + } + _ => panic!("Unexpected compound"), + } + } + } +} diff --git a/implementations/rust/preserves-schema/src/compiler/types.rs b/implementations/rust/preserves-schema/src/compiler/types.rs new file mode 100644 index 0000000..7fb0f40 --- /dev/null +++ b/implementations/rust/preserves-schema/src/compiler/types.rs @@ -0,0 +1,175 @@ +use crate::*; +use crate::syntax::block::Emittable; +use crate::syntax::block::constructors::*; +use super::names; + +use preserves::value::{IOValue, NestedValue}; +use preserves::error::Error; + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum TDefinition { + Union(Vec<(String, TSimple)>), + Simple(TSimple), +} + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum TSimple { + Field(TField), + Record(TRecord), +} + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum TField { + Unit, + Array(Box), + Set(Box), + Map(Box, Box), + Ref(Vec), + Base(String), +} + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct TRecord(pub Vec<(String, TField)>); + +pub fn definition_type(d: &IOValue) -> Result { + if let Some(fs) = d.value().as_simple_record("or", Some(1)) { + let mut entries = Vec::new(); + for e in fs[0].value().to_sequence()?.iter() { + let e = e.value().to_sequence()?; + entries.push((e[0].value().to_string()?.to_owned(), simple_type(&e[1])?)); + } + Ok(TDefinition::Union(entries)) + } else if let Some(fs) = d.value().as_simple_record("and", Some(1)) { + Ok(TDefinition::Simple(record_type(fs[0].value().to_sequence()?)?)) + } else { + Ok(TDefinition::Simple(simple_type(d)?)) + } +} + +pub fn simple_type(p: &IOValue) -> Result { + if let Some(t) = field_type(p)? { + Ok(TSimple::Field(t)) + } else { + record_type(&vec![p.clone()]) + } +} + +pub fn record_type(ps: &Vec) -> Result { + let fs = gather_fields(ps, Vec::new())?; + if fs.is_empty() { + Ok(TSimple::Field(TField::Unit)) + } else { + Ok(TSimple::Record(TRecord(fs))) + } +} + +pub fn gather_fields(ps: &Vec, mut fs: Vec<(String, TField)>) -> + Result, Error> +{ + for p in ps.iter() { + fs = gather_field(p, fs)?; + } + Ok(fs) +} + +pub fn gather_field(p: &IOValue, mut fs: Vec<(String, TField)>) -> + Result, Error> +{ + if let Some(n) = p.value().as_simple_record("named", Some(2)) { + let name = n[0].value().to_symbol()?; + fs.push((name.to_owned(), field_type(&n[1])?.unwrap())); + Ok(fs) + } else if let Some(label_and_fields) = p.value().as_simple_record("rec", Some(2)) { + Ok(gather_field(&label_and_fields[1], gather_field(&label_and_fields[0], fs)?)?) + } else if let Some(tfs) = p.value().as_simple_record("tuple", Some(1)) { + Ok(gather_fields(tfs[0].value().to_sequence()?, fs)?) + } else if let Some(tfs) = p.value().as_simple_record("tuplePrefix", Some(2)) { + Ok(gather_field(&tfs[1], gather_fields(tfs[0].value().to_sequence()?, fs)?)?) + } else if let Some(dfs) = p.value().as_simple_record("dict", Some(1)) { + let es = dfs[0].value().to_dictionary()?; + for (_k, p) in es.iter() { + fs = gather_field(p, fs)?; + } + Ok(fs) + } else { + Ok(fs) + } +} + +pub fn field_type(p: &IOValue) -> Result, Error> { + if p.value().as_symbol() == Some(&"any".to_owned()) { + Ok(Some(TField::Base("preserves::value::IOValue".to_owned()))) + } else if let Some(fs) = p.value().as_simple_record("atom", Some(1)) { + match fs[0].value().as_symbol().unwrap().as_str() { + "Boolean" => Ok(Some(TField::Base("bool".to_owned()))), + "Float" => Ok(Some(TField::Base("f32".to_owned()))), + "Double" => Ok(Some(TField::Base("f64".to_owned()))), + "SignedInteger" => Ok(Some(TField::Base("preserves::value::signed_integer::SignedInteger".to_owned()))), + "String" => Ok(Some(TField::Base("std::string::String".to_owned()))), + "ByteString" => Ok(Some(TField::Base("std::vec::Vec".to_owned()))), + "Symbol" => Ok(Some(TField::Base("std::string::String".to_owned()))), + _ => Err(Error::Message("Unexpected AtomKind".to_owned())), + } + } else if let Some(_) = p.value().as_simple_record("embedded", Some(1)) { + Ok(Some(TField::Base("_ptr".to_owned()))) + } else if let Some(_) = p.value().as_simple_record("lit", Some(1)) { + Ok(Some(TField::Unit)) + } else if let Some(fs) = p.value().as_simple_record("seqof", Some(1)) { + Ok(Some(TField::Array(Box::new(field_type(&fs[0])?.unwrap())))) + } else if let Some(fs) = p.value().as_simple_record("setof", Some(1)) { + Ok(Some(TField::Set(Box::new(field_type(&fs[0])?.unwrap())))) + } else if let Some(fs) = p.value().as_simple_record("dictof", Some(2)) { + Ok(Some(TField::Map(Box::new(field_type(&fs[0])?.unwrap()), + Box::new(field_type(&fs[1])?.unwrap())))) + } else if let Some(fs) = p.value().as_simple_record("ref", Some(2)) { + let mut pieces = fs[0].value().to_sequence()?.iter() + .map(|v| v.value().to_symbol().map(String::to_owned)) + .collect::,_>>()?; + pieces.push(fs[1].value().to_symbol()?.to_owned()); + Ok(Some(TField::Ref(pieces))) + } else { + Ok(None) + } +} + +pub fn render_field_type(box_needed: bool, t: &TField) -> impl Emittable { + match t { + TField::Unit => seq!["()"], + TField::Array(t) => seq!["std::vec::Vec<", render_field_type(false, t), ">"], + TField::Set(t) => seq!["preserves::value::Set<", render_field_type(false, t), ">"], + TField::Map(k, v) => seq!["preserves::value::Map", + anglebrackets![render_field_type(false, k), + render_field_type(false, v)]], + TField::Ref(pieces) => + if box_needed { + seq!["std::boxed::Box", anglebrackets![names::render_ref(pieces.clone())]] + } else { + seq![names::render_ref(pieces.clone())] + }, + TField::Base(n) => seq![n.to_owned()], + } +} + +pub fn render_recordlike_type(is_struct: bool, n: &str, d: &TSimple) -> impl Emittable { + let semi = if is_struct { seq![";"] } else { seq![] }; + seq![names::render_constructor(n), match d { + TSimple::Record(TRecord(fs)) => seq![" ", braces( + fs.iter().map(|(n, d)| item( + seq![if is_struct { "pub " } else { "" }, + names::render_fieldname(n), ": ", render_field_type(true, d)] + )).collect())], + TSimple::Field(TField::Unit) => semi, + TSimple::Field(t) => seq![parens![render_field_type(true, t)], semi], + }] +} + +pub fn render_definition_type(n: &str, t: &TDefinition) -> impl Emittable { + seq!["#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)] ", + match t { + TDefinition::Union(items) => + seq!["pub enum ", names::render_constructor(n), " ", braces( + items.iter().map(|(n, d)| item(render_recordlike_type(false, n, d))).collect())], + TDefinition::Simple(s) => + seq!["pub struct ", render_recordlike_type(true, n, s)], + }] +} diff --git a/implementations/rust/preserves-schema/src/lib.rs b/implementations/rust/preserves-schema/src/lib.rs new file mode 100644 index 0000000..17d620e --- /dev/null +++ b/implementations/rust/preserves-schema/src/lib.rs @@ -0,0 +1,43 @@ +pub mod syntax; +pub mod compiler; +pub mod metaschema; + +#[cfg(test)] +mod tests { + #[test] + fn can_access_preserves_core() { + use preserves::value::*; + assert_eq!(format!("{:?}", UnwrappedIOValue::from(3 + 4)), "7"); + } + + #[test] + fn simple_rendering() { + use crate::*; + use crate::syntax::block::*; + + let code = semiblock![ + seq!["f", parens!["a", "b", "c"]], + seq!["f", parens!["a", "b", "c"]], + seq!["f", parens!["a", "b", "c"]], + seq!["f", parens!["a", "b", "c"]], + seq!["f", parens!["a", "b", "c"]], + seq!["f", parens!["a", "b", "c"]], + seq!["g", parens![]], + parens![] + ]; + println!("{}", Formatter::to_string(&code)); + } + + #[test] + fn metaschema_parsing() -> Result<(), std::io::Error> { + use preserves::value::Reader; + use std::convert::TryFrom; + + let mut f = std::fs::File::open("../../../schema/schema.bin")?; + let mut reader = preserves::value::PackedReader::decode_read(&mut f); + let schema = reader.demand_next(false)?; + println!("{:#?}", crate::metaschema::Schema::try_from(&schema)); + + Ok(()) + } +} diff --git a/implementations/rust/preserves-schema/src/metaschema.rs b/implementations/rust/preserves-schema/src/metaschema.rs new file mode 100644 index 0000000..0d58b0b --- /dev/null +++ b/implementations/rust/preserves-schema/src/metaschema.rs @@ -0,0 +1,532 @@ +#![allow(unused_parens)] + +use std::convert::TryFrom; +use preserves::value::{NestedValue, Reader}; +use lazy_static::lazy_static; + +lazy_static! { + pub static ref LIT15: preserves::value::IOValue = /* #f */ preserves::value::PackedReader::decode_bytes(&vec![128]).demand_next(false).unwrap(); + pub static ref LIT28: preserves::value::IOValue = /* 1 */ preserves::value::PackedReader::decode_bytes(&vec![145]).demand_next(false).unwrap(); + pub static ref LIT0: preserves::value::IOValue = /* Boolean */ preserves::value::PackedReader::decode_bytes(&vec![179, 7, 66, 111, 111, 108, 101, 97, 110]).demand_next(false).unwrap(); + pub static ref LIT5: preserves::value::IOValue = /* ByteString */ preserves::value::PackedReader::decode_bytes(&vec![179, 10, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103]).demand_next(false).unwrap(); + pub static ref LIT2: preserves::value::IOValue = /* Double */ preserves::value::PackedReader::decode_bytes(&vec![179, 6, 68, 111, 117, 98, 108, 101]).demand_next(false).unwrap(); + pub static ref LIT1: preserves::value::IOValue = /* Float */ preserves::value::PackedReader::decode_bytes(&vec![179, 5, 70, 108, 111, 97, 116]).demand_next(false).unwrap(); + pub static ref LIT3: preserves::value::IOValue = /* SignedInteger */ preserves::value::PackedReader::decode_bytes(&vec![179, 13, 83, 105, 103, 110, 101, 100, 73, 110, 116, 101, 103, 101, 114]).demand_next(false).unwrap(); + pub static ref LIT4: preserves::value::IOValue = /* String */ preserves::value::PackedReader::decode_bytes(&vec![179, 6, 83, 116, 114, 105, 110, 103]).demand_next(false).unwrap(); + pub static ref LIT6: preserves::value::IOValue = /* Symbol */ preserves::value::PackedReader::decode_bytes(&vec![179, 6, 83, 121, 109, 98, 111, 108]).demand_next(false).unwrap(); + pub static ref LIT14: preserves::value::IOValue = /* and */ preserves::value::PackedReader::decode_bytes(&vec![179, 3, 97, 110, 100]).demand_next(false).unwrap(); + pub static ref LIT21: preserves::value::IOValue = /* any */ preserves::value::PackedReader::decode_bytes(&vec![179, 3, 97, 110, 121]).demand_next(false).unwrap(); + pub static ref LIT22: preserves::value::IOValue = /* atom */ preserves::value::PackedReader::decode_bytes(&vec![179, 4, 97, 116, 111, 109]).demand_next(false).unwrap(); + pub static ref LIT8: preserves::value::IOValue = /* bundle */ preserves::value::PackedReader::decode_bytes(&vec![179, 6, 98, 117, 110, 100, 108, 101]).demand_next(false).unwrap(); + pub static ref LIT18: preserves::value::IOValue = /* definitions */ preserves::value::PackedReader::decode_bytes(&vec![179, 11, 100, 101, 102, 105, 110, 105, 116, 105, 111, 110, 115]).demand_next(false).unwrap(); + pub static ref LIT12: preserves::value::IOValue = /* dict */ preserves::value::PackedReader::decode_bytes(&vec![179, 4, 100, 105, 99, 116]).demand_next(false).unwrap(); + pub static ref LIT27: preserves::value::IOValue = /* dictof */ preserves::value::PackedReader::decode_bytes(&vec![179, 6, 100, 105, 99, 116, 111, 102]).demand_next(false).unwrap(); + pub static ref LIT23: preserves::value::IOValue = /* embedded */ preserves::value::PackedReader::decode_bytes(&vec![179, 8, 101, 109, 98, 101, 100, 100, 101, 100]).demand_next(false).unwrap(); + pub static ref LIT19: preserves::value::IOValue = /* embeddedType */ preserves::value::PackedReader::decode_bytes(&vec![179, 12, 101, 109, 98, 101, 100, 100, 101, 100, 84, 121, 112, 101]).demand_next(false).unwrap(); + pub static ref LIT24: preserves::value::IOValue = /* lit */ preserves::value::PackedReader::decode_bytes(&vec![179, 3, 108, 105, 116]).demand_next(false).unwrap(); + pub static ref LIT7: preserves::value::IOValue = /* named */ preserves::value::PackedReader::decode_bytes(&vec![179, 5, 110, 97, 109, 101, 100]).demand_next(false).unwrap(); + pub static ref LIT13: preserves::value::IOValue = /* or */ preserves::value::PackedReader::decode_bytes(&vec![179, 2, 111, 114]).demand_next(false).unwrap(); + pub static ref LIT9: preserves::value::IOValue = /* rec */ preserves::value::PackedReader::decode_bytes(&vec![179, 3, 114, 101, 99]).demand_next(false).unwrap(); + pub static ref LIT16: preserves::value::IOValue = /* ref */ preserves::value::PackedReader::decode_bytes(&vec![179, 3, 114, 101, 102]).demand_next(false).unwrap(); + pub static ref LIT17: preserves::value::IOValue = /* schema */ preserves::value::PackedReader::decode_bytes(&vec![179, 6, 115, 99, 104, 101, 109, 97]).demand_next(false).unwrap(); + pub static ref LIT25: preserves::value::IOValue = /* seqof */ preserves::value::PackedReader::decode_bytes(&vec![179, 5, 115, 101, 113, 111, 102]).demand_next(false).unwrap(); + pub static ref LIT26: preserves::value::IOValue = /* setof */ preserves::value::PackedReader::decode_bytes(&vec![179, 5, 115, 101, 116, 111, 102]).demand_next(false).unwrap(); + pub static ref LIT10: preserves::value::IOValue = /* tuple */ preserves::value::PackedReader::decode_bytes(&vec![179, 5, 116, 117, 112, 108, 101]).demand_next(false).unwrap(); + pub static ref LIT11: preserves::value::IOValue = /* tuplePrefix */ preserves::value::PackedReader::decode_bytes(&vec![179, 11, 116, 117, 112, 108, 101, 80, 114, 101, 102, 105, 120]).demand_next(false).unwrap(); + pub static ref LIT20: preserves::value::IOValue = /* version */ preserves::value::PackedReader::decode_bytes(&vec![179, 7, 118, 101, 114, 115, 105, 111, 110]).demand_next(false).unwrap(); +} + +#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)] pub enum AtomKind {Boolean, Float, Double, SignedInteger, String, ByteString, Symbol} + +#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)] pub struct Binding {pub name: std::string::String, pub pattern: std::boxed::Box} + +#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)] pub struct Bundle {pub modules: std::boxed::Box} + +#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)] pub enum CompoundPattern { + Rec {label: std::boxed::Box, fields: std::boxed::Box}, + Tuple {patterns: std::vec::Vec}, + TuplePrefix { + fixed: std::vec::Vec, + variable: std::boxed::Box + }, + Dict {entries: std::boxed::Box} +} + +#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)] pub enum Definition { + Or { + pattern_0: std::boxed::Box, + pattern_1: std::boxed::Box, + pattern_n: std::vec::Vec + }, + And { + pattern_0: std::boxed::Box, + pattern_1: std::boxed::Box, + pattern_n: std::vec::Vec + }, + Pattern(std::boxed::Box) +} + +#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)] pub struct Definitions(preserves::value::Map); + +#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)] pub struct DictionaryEntries(preserves::value::Map); + +#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)] pub enum EmbeddedTypeName {Ref(std::boxed::Box), False} + +#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)] pub struct ModulePath(std::vec::Vec); + +#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)] pub struct Modules(preserves::value::Map); + +#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)] pub struct NamedAlternative {pub variant_label: std::string::String, pub pattern: std::boxed::Box} + +#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)] pub enum NamedPattern {Named(std::boxed::Box), Anonymous(std::boxed::Box)} + +#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)] pub enum NamedSimplePattern {Named(std::boxed::Box), Anonymous(std::boxed::Box)} + +#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)] pub enum Pattern { + SimplePattern(std::boxed::Box), + CompoundPattern(std::boxed::Box) +} + +#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)] pub struct Ref {pub module: std::boxed::Box, pub name: std::string::String} + +#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)] pub struct Schema { + pub definitions: std::boxed::Box, + pub embedded_type: std::boxed::Box, + pub version: std::boxed::Box +} + +#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)] pub enum SimplePattern { + Any, + Atom {atom_kind: std::boxed::Box}, + Embedded {interface: std::boxed::Box}, + Lit {value: preserves::value::IOValue}, + Seqof {pattern: std::boxed::Box}, + Setof {pattern: std::boxed::Box}, + Dictof {key: std::boxed::Box, value: std::boxed::Box}, + Ref(std::boxed::Box) +} + +#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)] pub struct Version; + +fn _parse_atom_kind_boolean(value: &preserves::value::IOValue) -> std::result::Result {if value != &*LIT0 { return Err(()); } let _tmp0 = (); Ok(AtomKind::Boolean)} + +fn _parse_atom_kind_float(value: &preserves::value::IOValue) -> std::result::Result {if value != &*LIT1 { return Err(()); } let _tmp0 = (); Ok(AtomKind::Float)} + +fn _parse_atom_kind_double(value: &preserves::value::IOValue) -> std::result::Result {if value != &*LIT2 { return Err(()); } let _tmp0 = (); Ok(AtomKind::Double)} + +fn _parse_atom_kind_signed_integer(value: &preserves::value::IOValue) -> std::result::Result { + if value != &*LIT3 { return Err(()); } + let _tmp0 = (); + Ok(AtomKind::SignedInteger) +} + +fn _parse_atom_kind_string(value: &preserves::value::IOValue) -> std::result::Result {if value != &*LIT4 { return Err(()); } let _tmp0 = (); Ok(AtomKind::String)} + +fn _parse_atom_kind_byte_string(value: &preserves::value::IOValue) -> std::result::Result { + if value != &*LIT5 { return Err(()); } + let _tmp0 = (); + Ok(AtomKind::ByteString) +} + +fn _parse_atom_kind_symbol(value: &preserves::value::IOValue) -> std::result::Result {if value != &*LIT6 { return Err(()); } let _tmp0 = (); Ok(AtomKind::Symbol)} + +impl std::convert::TryFrom<&preserves::value::IOValue> for AtomKind { + type Error = (); + fn try_from(value: &preserves::value::IOValue) -> std::result::Result { + if let Ok(r) = _parse_atom_kind_boolean(value) { return Ok(r); } + if let Ok(r) = _parse_atom_kind_float(value) { return Ok(r); } + if let Ok(r) = _parse_atom_kind_double(value) { return Ok(r); } + if let Ok(r) = _parse_atom_kind_signed_integer(value) { return Ok(r); } + if let Ok(r) = _parse_atom_kind_string(value) { return Ok(r); } + if let Ok(r) = _parse_atom_kind_byte_string(value) { return Ok(r); } + if let Ok(r) = _parse_atom_kind_symbol(value) { return Ok(r); } + Err(()) + } +} + +impl std::convert::TryFrom<&preserves::value::IOValue> for Binding { + type Error = (); + fn try_from(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp1 = value.value().to_record(None).map_err(|_| ())?; + if _tmp1.label() != &*LIT7 { return Err(()); } + let _tmp2 = (); + if _tmp1.fields().len() - 0 < 2 { return Err(()); } + let _tmp5 = (&_tmp1.fields()[0]).value().to_symbol().map_err(|_| ())?; + let _tmp7 = SimplePattern::try_from((&_tmp1.fields()[1]))?; + Ok(Binding {name: _tmp5.clone(), pattern: std::boxed::Box::new(_tmp7)}) + } +} + +impl std::convert::TryFrom<&preserves::value::IOValue> for Bundle { + type Error = (); + fn try_from(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp1 = value.value().to_record(None).map_err(|_| ())?; + if _tmp1.label() != &*LIT8 { return Err(()); } + let _tmp2 = (); + if _tmp1.fields().len() - 0 < 1 { return Err(()); } + let _tmp5 = Modules::try_from((&_tmp1.fields()[0]))?; + Ok(Bundle {modules: std::boxed::Box::new(_tmp5)}) + } +} + +fn _parse_compound_pattern_rec(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp1 = value.value().to_record(None).map_err(|_| ())?; + if _tmp1.label() != &*LIT9 { return Err(()); } + let _tmp2 = (); + if _tmp1.fields().len() - 0 < 2 { return Err(()); } + let _tmp5 = NamedPattern::try_from((&_tmp1.fields()[0]))?; + let _tmp7 = NamedPattern::try_from((&_tmp1.fields()[1]))?; + Ok(CompoundPattern::Rec {label: std::boxed::Box::new(_tmp5), fields: std::boxed::Box::new(_tmp7)}) +} + +fn _parse_compound_pattern_tuple(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp1 = value.value().to_record(None).map_err(|_| ())?; + if _tmp1.label() != &*LIT10 { return Err(()); } + let _tmp2 = (); + if _tmp1.fields().len() - 0 < 1 { return Err(()); } + let _tmp6 = (&_tmp1.fields()[0]).value().to_sequence().map_err(|_| ())?; + let mut _tmp5 = std::vec::Vec::new(); + for _tmp7 in &_tmp6[0..] {let _tmp8 = NamedPattern::try_from(_tmp7)?; _tmp5.push(_tmp8);} + Ok(CompoundPattern::Tuple {patterns: _tmp5}) +} + +fn _parse_compound_pattern_tuple_prefix(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp1 = value.value().to_record(None).map_err(|_| ())?; + if _tmp1.label() != &*LIT11 { return Err(()); } + let _tmp2 = (); + if _tmp1.fields().len() - 0 < 2 { return Err(()); } + let _tmp6 = (&_tmp1.fields()[0]).value().to_sequence().map_err(|_| ())?; + let mut _tmp5 = std::vec::Vec::new(); + for _tmp7 in &_tmp6[0..] {let _tmp8 = NamedPattern::try_from(_tmp7)?; _tmp5.push(_tmp8);} + let _tmp10 = NamedSimplePattern::try_from((&_tmp1.fields()[1]))?; + Ok(CompoundPattern::TuplePrefix {fixed: _tmp5, variable: std::boxed::Box::new(_tmp10)}) +} + +fn _parse_compound_pattern_dict(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp1 = value.value().to_record(None).map_err(|_| ())?; + if _tmp1.label() != &*LIT12 { return Err(()); } + let _tmp2 = (); + if _tmp1.fields().len() - 0 < 1 { return Err(()); } + let _tmp5 = DictionaryEntries::try_from((&_tmp1.fields()[0]))?; + Ok(CompoundPattern::Dict {entries: std::boxed::Box::new(_tmp5)}) +} + +impl std::convert::TryFrom<&preserves::value::IOValue> for CompoundPattern { + type Error = (); + fn try_from(value: &preserves::value::IOValue) -> std::result::Result { + if let Ok(r) = _parse_compound_pattern_rec(value) { return Ok(r); } + if let Ok(r) = _parse_compound_pattern_tuple(value) { return Ok(r); } + if let Ok(r) = _parse_compound_pattern_tuple_prefix(value) { return Ok(r); } + if let Ok(r) = _parse_compound_pattern_dict(value) { return Ok(r); } + Err(()) + } +} + +fn _parse_definition_or(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp1 = value.value().to_record(None).map_err(|_| ())?; + if _tmp1.label() != &*LIT13 { return Err(()); } + let _tmp2 = (); + if _tmp1.fields().len() - 0 < 1 { return Err(()); } + let _tmp5 = (&_tmp1.fields()[0]).value().to_sequence().map_err(|_| ())?; + if _tmp5.len() - 0 < 2 { return Err(()); } + let _tmp7 = NamedAlternative::try_from((&_tmp5[0]))?; + let _tmp9 = NamedAlternative::try_from((&_tmp5[1]))?; + let mut _tmp11 = std::vec::Vec::new(); + for _tmp12 in &_tmp5[2..] {let _tmp13 = NamedAlternative::try_from(_tmp12)?; _tmp11.push(_tmp13);} + Ok(Definition::Or { + pattern_0: std::boxed::Box::new(_tmp7), + pattern_1: std::boxed::Box::new(_tmp9), + pattern_n: _tmp11 + }) +} + +fn _parse_definition_and(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp1 = value.value().to_record(None).map_err(|_| ())?; + if _tmp1.label() != &*LIT14 { return Err(()); } + let _tmp2 = (); + if _tmp1.fields().len() - 0 < 1 { return Err(()); } + let _tmp5 = (&_tmp1.fields()[0]).value().to_sequence().map_err(|_| ())?; + if _tmp5.len() - 0 < 2 { return Err(()); } + let _tmp7 = NamedPattern::try_from((&_tmp5[0]))?; + let _tmp9 = NamedPattern::try_from((&_tmp5[1]))?; + let mut _tmp11 = std::vec::Vec::new(); + for _tmp12 in &_tmp5[2..] {let _tmp13 = NamedPattern::try_from(_tmp12)?; _tmp11.push(_tmp13);} + Ok(Definition::And { + pattern_0: std::boxed::Box::new(_tmp7), + pattern_1: std::boxed::Box::new(_tmp9), + pattern_n: _tmp11 + }) +} + +fn _parse_definition_pattern(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp0 = Pattern::try_from(value)?; + Ok(Definition::Pattern(std::boxed::Box::new(_tmp0))) +} + +impl std::convert::TryFrom<&preserves::value::IOValue> for Definition { + type Error = (); + fn try_from(value: &preserves::value::IOValue) -> std::result::Result { + if let Ok(r) = _parse_definition_or(value) { return Ok(r); } + if let Ok(r) = _parse_definition_and(value) { return Ok(r); } + if let Ok(r) = _parse_definition_pattern(value) { return Ok(r); } + Err(()) + } +} + +impl std::convert::TryFrom<&preserves::value::IOValue> for Definitions { + type Error = (); + fn try_from(value: &preserves::value::IOValue) -> std::result::Result { + let mut _tmp0 = preserves::value::Map::new(); + for (_tmp1, _tmp2) in value.value().to_dictionary().map_err(|_| ())? { + let _tmp3 = _tmp1.value().to_symbol().map_err(|_| ())?; + let _tmp4 = Definition::try_from(_tmp2)?; + _tmp0.insert(_tmp3.clone(), _tmp4); + } + Ok(Definitions(_tmp0)) + } +} + +impl std::convert::TryFrom<&preserves::value::IOValue> for DictionaryEntries { + type Error = (); + fn try_from(value: &preserves::value::IOValue) -> std::result::Result { + let mut _tmp0 = preserves::value::Map::new(); + for (_tmp1, _tmp2) in value.value().to_dictionary().map_err(|_| ())? { + let _tmp3 = _tmp1; + let _tmp4 = NamedSimplePattern::try_from(_tmp2)?; + _tmp0.insert(_tmp3.clone(), _tmp4); + } + Ok(DictionaryEntries(_tmp0)) + } +} + +fn _parse_embedded_type_name_ref(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp0 = Ref::try_from(value)?; + Ok(EmbeddedTypeName::Ref(std::boxed::Box::new(_tmp0))) +} + +fn _parse_embedded_type_name_false(value: &preserves::value::IOValue) -> std::result::Result { + if value != &*LIT15 { return Err(()); } + let _tmp0 = (); + Ok(EmbeddedTypeName::False) +} + +impl std::convert::TryFrom<&preserves::value::IOValue> for EmbeddedTypeName { + type Error = (); + fn try_from(value: &preserves::value::IOValue) -> std::result::Result { + if let Ok(r) = _parse_embedded_type_name_ref(value) { return Ok(r); } + if let Ok(r) = _parse_embedded_type_name_false(value) { return Ok(r); } + Err(()) + } +} + +impl std::convert::TryFrom<&preserves::value::IOValue> for ModulePath { + type Error = (); + fn try_from(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp1 = value.value().to_sequence().map_err(|_| ())?; + let mut _tmp0 = std::vec::Vec::new(); + for _tmp2 in &_tmp1[0..] { + let _tmp3 = _tmp2.value().to_symbol().map_err(|_| ())?; + _tmp0.push(_tmp3.clone()); + } + Ok(ModulePath(_tmp0)) + } +} + +impl std::convert::TryFrom<&preserves::value::IOValue> for Modules { + type Error = (); + fn try_from(value: &preserves::value::IOValue) -> std::result::Result { + let mut _tmp0 = preserves::value::Map::new(); + for (_tmp1, _tmp2) in value.value().to_dictionary().map_err(|_| ())? { + let _tmp3 = ModulePath::try_from(_tmp1)?; + let _tmp4 = Schema::try_from(_tmp2)?; + _tmp0.insert(_tmp3, _tmp4); + } + Ok(Modules(_tmp0)) + } +} + +impl std::convert::TryFrom<&preserves::value::IOValue> for NamedAlternative { + type Error = (); + fn try_from(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp1 = value.value().to_sequence().map_err(|_| ())?; + if _tmp1.len() - 0 < 2 { return Err(()); } + let _tmp3 = (&_tmp1[0]).value().to_string().map_err(|_| ())?; + let _tmp5 = Pattern::try_from((&_tmp1[1]))?; + Ok(NamedAlternative {variant_label: _tmp3.clone(), pattern: std::boxed::Box::new(_tmp5)}) + } +} + +fn _parse_named_pattern_named(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp0 = Binding::try_from(value)?; + Ok(NamedPattern::Named(std::boxed::Box::new(_tmp0))) +} + +fn _parse_named_pattern_anonymous(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp0 = Pattern::try_from(value)?; + Ok(NamedPattern::Anonymous(std::boxed::Box::new(_tmp0))) +} + +impl std::convert::TryFrom<&preserves::value::IOValue> for NamedPattern { + type Error = (); + fn try_from(value: &preserves::value::IOValue) -> std::result::Result { + if let Ok(r) = _parse_named_pattern_named(value) { return Ok(r); } + if let Ok(r) = _parse_named_pattern_anonymous(value) { return Ok(r); } + Err(()) + } +} + +fn _parse_named_simple_pattern_named(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp0 = Binding::try_from(value)?; + Ok(NamedSimplePattern::Named(std::boxed::Box::new(_tmp0))) +} + +fn _parse_named_simple_pattern_anonymous(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp0 = SimplePattern::try_from(value)?; + Ok(NamedSimplePattern::Anonymous(std::boxed::Box::new(_tmp0))) +} + +impl std::convert::TryFrom<&preserves::value::IOValue> for NamedSimplePattern { + type Error = (); + fn try_from(value: &preserves::value::IOValue) -> std::result::Result { + if let Ok(r) = _parse_named_simple_pattern_named(value) { return Ok(r); } + if let Ok(r) = _parse_named_simple_pattern_anonymous(value) { return Ok(r); } + Err(()) + } +} + +fn _parse_pattern_simple_pattern(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp0 = SimplePattern::try_from(value)?; + Ok(Pattern::SimplePattern(std::boxed::Box::new(_tmp0))) +} + +fn _parse_pattern_compound_pattern(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp0 = CompoundPattern::try_from(value)?; + Ok(Pattern::CompoundPattern(std::boxed::Box::new(_tmp0))) +} + +impl std::convert::TryFrom<&preserves::value::IOValue> for Pattern { + type Error = (); + fn try_from(value: &preserves::value::IOValue) -> std::result::Result { + if let Ok(r) = _parse_pattern_simple_pattern(value) { return Ok(r); } + if let Ok(r) = _parse_pattern_compound_pattern(value) { return Ok(r); } + Err(()) + } +} + +impl std::convert::TryFrom<&preserves::value::IOValue> for Ref { + type Error = (); + fn try_from(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp1 = value.value().to_record(None).map_err(|_| ())?; + if _tmp1.label() != &*LIT16 { return Err(()); } + let _tmp2 = (); + if _tmp1.fields().len() - 0 < 2 { return Err(()); } + let _tmp5 = ModulePath::try_from((&_tmp1.fields()[0]))?; + let _tmp7 = (&_tmp1.fields()[1]).value().to_symbol().map_err(|_| ())?; + Ok(Ref {module: std::boxed::Box::new(_tmp5), name: _tmp7.clone()}) + } +} + +impl std::convert::TryFrom<&preserves::value::IOValue> for Schema { + type Error = (); + fn try_from(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp1 = value.value().to_record(None).map_err(|_| ())?; + if _tmp1.label() != &*LIT17 { return Err(()); } + let _tmp2 = (); + if _tmp1.fields().len() - 0 < 1 { return Err(()); } + let _tmp5 = (&_tmp1.fields()[0]).value().to_dictionary().map_err(|_| ())?; + let _tmp6 = _tmp5.get(&*LIT18).ok_or(())?; + let _tmp8 = Definitions::try_from(_tmp6)?; + let _tmp9 = _tmp5.get(&*LIT19).ok_or(())?; + let _tmp11 = EmbeddedTypeName::try_from(_tmp9)?; + let _tmp12 = _tmp5.get(&*LIT20).ok_or(())?; + let _tmp14 = Version::try_from(_tmp12)?; + Ok(Schema { + definitions: std::boxed::Box::new(_tmp8), + embedded_type: std::boxed::Box::new(_tmp11), + version: std::boxed::Box::new(_tmp14) + }) + } +} + +fn _parse_simple_pattern_any(value: &preserves::value::IOValue) -> std::result::Result {if value != &*LIT21 { return Err(()); } let _tmp0 = (); Ok(SimplePattern::Any)} + +fn _parse_simple_pattern_atom(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp1 = value.value().to_record(None).map_err(|_| ())?; + if _tmp1.label() != &*LIT22 { return Err(()); } + let _tmp2 = (); + if _tmp1.fields().len() - 0 < 1 { return Err(()); } + let _tmp5 = AtomKind::try_from((&_tmp1.fields()[0]))?; + Ok(SimplePattern::Atom {atom_kind: std::boxed::Box::new(_tmp5)}) +} + +fn _parse_simple_pattern_embedded(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp1 = value.value().to_record(None).map_err(|_| ())?; + if _tmp1.label() != &*LIT23 { return Err(()); } + let _tmp2 = (); + if _tmp1.fields().len() - 0 < 1 { return Err(()); } + let _tmp5 = SimplePattern::try_from((&_tmp1.fields()[0]))?; + Ok(SimplePattern::Embedded {interface: std::boxed::Box::new(_tmp5)}) +} + +fn _parse_simple_pattern_lit(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp1 = value.value().to_record(None).map_err(|_| ())?; + if _tmp1.label() != &*LIT24 { return Err(()); } + let _tmp2 = (); + if _tmp1.fields().len() - 0 < 1 { return Err(()); } + let _tmp5 = (&_tmp1.fields()[0]); + Ok(SimplePattern::Lit {value: _tmp5.clone()}) +} + +fn _parse_simple_pattern_seqof(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp1 = value.value().to_record(None).map_err(|_| ())?; + if _tmp1.label() != &*LIT25 { return Err(()); } + let _tmp2 = (); + if _tmp1.fields().len() - 0 < 1 { return Err(()); } + let _tmp5 = SimplePattern::try_from((&_tmp1.fields()[0]))?; + Ok(SimplePattern::Seqof {pattern: std::boxed::Box::new(_tmp5)}) +} + +fn _parse_simple_pattern_setof(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp1 = value.value().to_record(None).map_err(|_| ())?; + if _tmp1.label() != &*LIT26 { return Err(()); } + let _tmp2 = (); + if _tmp1.fields().len() - 0 < 1 { return Err(()); } + let _tmp5 = SimplePattern::try_from((&_tmp1.fields()[0]))?; + Ok(SimplePattern::Setof {pattern: std::boxed::Box::new(_tmp5)}) +} + +fn _parse_simple_pattern_dictof(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp1 = value.value().to_record(None).map_err(|_| ())?; + if _tmp1.label() != &*LIT27 { return Err(()); } + let _tmp2 = (); + if _tmp1.fields().len() - 0 < 2 { return Err(()); } + let _tmp5 = SimplePattern::try_from((&_tmp1.fields()[0]))?; + let _tmp7 = SimplePattern::try_from((&_tmp1.fields()[1]))?; + Ok(SimplePattern::Dictof {key: std::boxed::Box::new(_tmp5), value: std::boxed::Box::new(_tmp7)}) +} + +fn _parse_simple_pattern_ref(value: &preserves::value::IOValue) -> std::result::Result { + let _tmp0 = Ref::try_from(value)?; + Ok(SimplePattern::Ref(std::boxed::Box::new(_tmp0))) +} + +impl std::convert::TryFrom<&preserves::value::IOValue> for SimplePattern { + type Error = (); + fn try_from(value: &preserves::value::IOValue) -> std::result::Result { + if let Ok(r) = _parse_simple_pattern_any(value) { return Ok(r); } + if let Ok(r) = _parse_simple_pattern_atom(value) { return Ok(r); } + if let Ok(r) = _parse_simple_pattern_embedded(value) { return Ok(r); } + if let Ok(r) = _parse_simple_pattern_lit(value) { return Ok(r); } + if let Ok(r) = _parse_simple_pattern_seqof(value) { return Ok(r); } + if let Ok(r) = _parse_simple_pattern_setof(value) { return Ok(r); } + if let Ok(r) = _parse_simple_pattern_dictof(value) { return Ok(r); } + if let Ok(r) = _parse_simple_pattern_ref(value) { return Ok(r); } + Err(()) + } +} + +impl std::convert::TryFrom<&preserves::value::IOValue> for Version { + type Error = (); + fn try_from(value: &preserves::value::IOValue) -> std::result::Result {if value != &*LIT28 { return Err(()); } let _tmp0 = (); Ok(Version)} +} + diff --git a/implementations/rust/preserves-schema/src/syntax/block.rs b/implementations/rust/preserves-schema/src/syntax/block.rs new file mode 100644 index 0000000..25ed061 --- /dev/null +++ b/implementations/rust/preserves-schema/src/syntax/block.rs @@ -0,0 +1,274 @@ +use std::str; + +pub const DEFAULT_WIDTH: usize = 80; + +pub trait Emittable: std::fmt::Debug { + fn write_on(&self, f: &mut Formatter); +} + +pub type Item = std::rc::Rc; + +#[derive(Clone)] +pub struct Sequence { + pub items: Vec, + pub separator: &'static str, + pub terminator: &'static str, +} + +#[derive(Clone)] +pub struct Grouping { + pub sequence: Sequence, + pub open: &'static str, + pub close: &'static str, +} + +pub struct Formatter { + pub width: usize, + indent_delta: String, + current_indent: String, + pub buffer: String, +} + +impl Formatter { + pub fn new() -> Self { + Formatter { + width: DEFAULT_WIDTH, + indent_delta: " ".to_owned(), + current_indent: "\n".to_owned(), + buffer: String::new(), + } + } + + pub fn copy_empty(&self) -> Formatter { + Formatter { + width: self.width, + indent_delta: self.indent_delta.clone(), + current_indent: self.current_indent.clone(), + buffer: String::new(), + } + } + + pub fn indent_size(self) -> usize { + self.indent_delta.len() + } + + pub fn set_indent_size(&mut self, n: usize) { + self.indent_delta = str::repeat(" ", n) + } + + pub fn write(&mut self, e: E) { + e.write_on(self) + } + + pub fn newline(&mut self) { + self.buffer.push_str(&self.current_indent) + } + + pub fn to_string(e: E) -> String { + let mut f = Formatter::new(); + f.write(e); + f.buffer + } + + pub fn with_indent R>(&mut self, f: F) -> R { + let old_indent = self.current_indent.clone(); + self.current_indent += &self.indent_delta; + let r = f(self); + self.current_indent = old_indent; + r + } +} + +//--------------------------------------------------------------------------- + +impl Emittable for &str { + fn write_on(&self, f: &mut Formatter) { + f.buffer.push_str(self) + } +} + +impl Emittable for String { + fn write_on(&self, f: &mut Formatter) { + f.write(self.as_str()) + } +} + +impl<'a, E: Emittable> Emittable for &'a Vec where &'a E: Emittable { + fn write_on(&self, f: &mut Formatter) { + for e in self.iter() { + f.write(e) + } + } +} + +impl Emittable for Sequence { + fn write_on(&self, f: &mut Formatter) { + let mut need_sep = false; + for e in self.items.iter() { + if need_sep { + self.separator.write_on(f) + } else { + need_sep = true + } + e.write_on(f) + } + self.terminator.write_on(f) + } +} + +impl Emittable for Grouping { + fn write_on(&self, f: &mut Formatter) { + let mut g = f.copy_empty(); + self.open.write_on(&mut g); + g.write(&self.sequence); + self.close.write_on(&mut g); + let s = g.buffer; + if s.len() <= f.width { + f.write(&s) + } else { + self.open.write_on(f); + if !self.sequence.items.is_empty() { + f.with_indent(|f| { + let mut i = self.sequence.items.len(); + for e in self.sequence.items.iter() { + f.newline(); + e.write_on(f); + let delim = if i == 1 { self.sequence.terminator } else { self.sequence.separator }; + delim.trim_end().write_on(f); + i = i - 1; + } + }); + f.newline() + } + self.close.write_on(f); + } + } +} + +impl<'a, E: Emittable> Emittable for &'a E { + fn write_on(&self, f: &mut Formatter) { + (*self).write_on(f) + } +} + +impl Emittable for Item { + fn write_on(&self, f: &mut Formatter) { + (**self).write_on(f) + } +} + +impl std::fmt::Debug for Sequence { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + f.write_str(&Formatter::to_string(self)) + } +} + +impl std::fmt::Debug for Grouping { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + f.write_str(&Formatter::to_string(self)) + } +} + +//--------------------------------------------------------------------------- + +pub mod constructors { + use super::Sequence; + use super::Grouping; + use super::Item; + use super::Emittable; + + pub fn item(i: E) -> Item { + std::rc::Rc::new(i) + } + + pub fn name(pieces: Vec) -> Sequence { + Sequence { items: pieces, separator: "::", terminator: "" } + } + + pub fn seq(items: Vec) -> Sequence { + Sequence { items: items, separator: "", terminator: "" } + } + + pub fn commas(items: Vec) -> Sequence { + Sequence { items: items, separator: ", ", terminator: "" } + } + + pub fn parens(items: Vec) -> Grouping { + Grouping { sequence: commas(items), open: "(", close: ")" } + } + + pub fn brackets(items: Vec) -> Grouping { + Grouping { sequence: commas(items), open: "[", close: "]" } + } + + pub fn anglebrackets(items: Vec) -> Grouping { + Grouping { sequence: commas(items), open: "<", close: ">" } + } + + pub fn braces(items: Vec) -> Grouping { + Grouping { sequence: commas(items), open: "{", close: "}" } + } + + pub fn block(items: Vec) -> Grouping { + Grouping { + sequence: Sequence { items: items, separator: " ", terminator: "" }, + open: "{", + close: "}", + } + } + + pub fn semiblock(items: Vec) -> Grouping { + Grouping { + sequence: Sequence { items: items, separator: "; ", terminator: "" }, + open: "{", + close: "}", + } + } +} + +pub mod macros { + #[macro_export] + macro_rules! name { + ($($item:expr),*) => {crate::syntax::block::constructors::name(vec![$(std::rc::Rc::new($item)),*])} + } + + #[macro_export] + macro_rules! seq { + ($($item:expr),*) => {crate::syntax::block::constructors::seq(vec![$(std::rc::Rc::new($item)),*])} + } + + #[macro_export] + macro_rules! commas { + ($($item:expr),*) => {crate::syntax::block::constructors::commas(vec![$(std::rc::Rc::new($item)),*])} + } + + #[macro_export] + macro_rules! parens { + ($($item:expr),*) => {crate::syntax::block::constructors::parens(vec![$(std::rc::Rc::new($item)),*])} + } + + #[macro_export] + macro_rules! brackets { + ($($item:expr),*) => {crate::syntax::block::constructors::brackets(vec![$(std::rc::Rc::new($item)),*])} + } + + #[macro_export] + macro_rules! anglebrackets { + ($($item:expr),*) => {crate::syntax::block::constructors::anglebrackets(vec![$(std::rc::Rc::new($item)),*])} + } + + #[macro_export] + macro_rules! braces { + ($($item:expr),*) => {crate::syntax::block::constructors::braces(vec![$(std::rc::Rc::new($item)),*])} + } + + #[macro_export] + macro_rules! block { + ($($item:expr),*) => {crate::syntax::block::constructors::block(vec![$(std::rc::Rc::new($item)),*])} + } + + #[macro_export] + macro_rules! semiblock { + ($($item:expr),*) => {crate::syntax::block::constructors::semiblock(vec![$(std::rc::Rc::new($item)),*])} + } +} diff --git a/implementations/rust/preserves-schema/src/syntax/mod.rs b/implementations/rust/preserves-schema/src/syntax/mod.rs new file mode 100644 index 0000000..a863eaa --- /dev/null +++ b/implementations/rust/preserves-schema/src/syntax/mod.rs @@ -0,0 +1 @@ +pub mod block; diff --git a/implementations/rust/preserves/src/value/mod.rs b/implementations/rust/preserves/src/value/mod.rs index da8626f..b4f074d 100644 --- a/implementations/rust/preserves/src/value/mod.rs +++ b/implementations/rust/preserves/src/value/mod.rs @@ -21,6 +21,7 @@ pub use repr::Map; pub use repr::NestedValue; pub use repr::PlainValue; pub use repr::RcValue; +pub use repr::Record; pub use repr::Set; pub use repr::UnwrappedIOValue; pub use repr::Value; diff --git a/implementations/rust/preserves/src/value/repr.rs b/implementations/rust/preserves/src/value/repr.rs index 4e16924..15811f8 100644 --- a/implementations/rust/preserves/src/value/repr.rs +++ b/implementations/rust/preserves/src/value/repr.rs @@ -720,6 +720,22 @@ impl, D: Domain> Value { self.as_dictionary().ok_or_else(|| self.expected(ExpectedKind::Dictionary)) } + pub fn is_embedded(&self) -> bool { + self.as_embedded().is_some() + } + + pub fn as_embedded(&self) -> Option<&D> { + if let Value::Domain(ref d) = *self { + Some(d) + } else { + None + } + } + + pub fn to_embedded(&self) -> Result<&D, Error> { + self.as_embedded().ok_or_else(|| self.expected(ExpectedKind::Embedded)) + } + pub fn copy_via, E: Domain, F>(&self, f: &F) -> Value where F: Fn(&D) -> Value