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![] }; let ppub = if is_struct { "pub " } else { "" }; seq![names::render_constructor(n), match d { TSimple::Record(TRecord(fs)) => seq![" ", braces( fs.iter().map(|(n, d)| item( seq![ppub, names::render_fieldname(n), ": ", render_field_type(true, d)] )).collect())], TSimple::Field(TField::Unit) => semi, TSimple::Field(t) => seq![parens![seq![ppub, render_field_type(true, t)]], semi], }] } pub fn render_definition_type(n: &str, t: &TDefinition) -> impl Emittable { seq!["#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)]\n", 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)], }] }