use crate::*; use crate::syntax::block::Emittable; use crate::syntax::block::constructors::*; use crate::gen::schema::*; use super::context::ModuleContext; use super::names; #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] pub enum TDefinition { Union(Vec<(String, TSimple)>), Simple(TSimple), } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] pub enum TSimple { Field(TField), Record(TRecord), } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] pub enum TField { Unit, Array(Box), Set(Box), Map(Box, Box), Ref(Vec, String), Base(String), } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] pub struct TRecord(pub Vec<(String, TField)>); pub fn definition_type(d: &Definition) -> TDefinition { match d { Definition::Or { pattern_0, pattern_1, pattern_n } => TDefinition::Union(or_definition_type(pattern_0, pattern_1, pattern_n)), Definition::And { pattern_0, pattern_1, pattern_n } => TDefinition::Simple(and_definition_type(pattern_0, pattern_1, pattern_n)), Definition::Pattern(p) => TDefinition::Simple(pattern_type(p)), } } pub fn or_definition_type( p0: &NamedAlternative, p1: &NamedAlternative, pn: &Vec, ) -> Vec<(String, TSimple)> { let mut entries = Vec::new(); entries.push((p0.variant_label.to_owned(), pattern_type(&p0.pattern))); entries.push((p1.variant_label.to_owned(), pattern_type(&p1.pattern))); for e in pn { entries.push((e.variant_label.to_owned(), pattern_type(&e.pattern))); } entries } pub fn and_definition_type( p0: &NamedPattern, p1: &NamedPattern, pn: &Vec, ) -> TSimple { let mut arms = vec![p0, p1]; arms.extend(pn); record_type(&arms) } pub fn pattern_type(p: &Pattern) -> TSimple { match p { Pattern::SimplePattern(p) => TSimple::Field(field_type(p)), Pattern::CompoundPattern(_) => record_type(&vec![&NamedPattern::Anonymous(Box::new(p.clone()))]), } } pub fn record_type(ps: &Vec<&NamedPattern>) -> TSimple { let fs = gather_fields(ps, Vec::new()); if fs.is_empty() { TSimple::Field(TField::Unit) } else { TSimple::Record(TRecord(fs)) } } pub fn gather_fields(ps: &Vec<&NamedPattern>, mut fs: Vec<(String, TField)>) -> Vec<(String, TField)> { for p in ps.iter() { fs = gather_field(p, fs); } fs } pub fn gather_field(p: &NamedPattern, mut fs: Vec<(String, TField)>) -> Vec<(String, TField)> { match p { NamedPattern::Named(b) => { let Binding { name, pattern } = &**b; fs.push((name.to_owned(), field_type(pattern))); fs }, NamedPattern::Anonymous(p) => match &**p { Pattern::SimplePattern(_) => fs, Pattern::CompoundPattern(c) => match &**c { CompoundPattern::Rec { label, fields } => gather_field(&*fields, gather_field(&*label, fs)), CompoundPattern::Tuple { patterns } => gather_fields(&patterns.iter().collect(), fs), CompoundPattern::TuplePrefix { fixed, variable } => gather_field(&promote(&**variable), gather_fields(&fixed.iter().collect(), fs)), CompoundPattern::Dict { entries } => { for (_k, p) in &entries.0 { fs = gather_field(&promote(&p), fs); } fs } } } } } pub fn promote(p: &NamedSimplePattern) -> NamedPattern { match p { NamedSimplePattern::Anonymous(p) => NamedPattern::Anonymous(Box::new(Pattern::SimplePattern(p.clone()))), NamedSimplePattern::Named(n) => NamedPattern::Named(n.clone()), } } pub fn field_type(p: &SimplePattern) -> TField { match p { SimplePattern::Any => TField::Base("preserves::value::IOValue".to_owned()), SimplePattern::Atom { atom_kind: k } => match **k { AtomKind::Boolean => TField::Base("bool".to_owned()), AtomKind::Float => TField::Base("f32".to_owned()), AtomKind::Double => TField::Base("f64".to_owned()), AtomKind::SignedInteger => TField::Base("preserves::value::signed_integer::SignedInteger".to_owned()), AtomKind::String => TField::Base("std::string::String".to_owned()), AtomKind::ByteString => TField::Base("std::vec::Vec".to_owned()), AtomKind::Symbol => TField::Base("std::string::String".to_owned()), }, SimplePattern::Embedded { .. } => TField::Base("_ptr".to_owned()), SimplePattern::Lit { .. } => TField::Unit, SimplePattern::Seqof { pattern: t } => TField::Array(Box::new(field_type(t))), SimplePattern::Setof { pattern: t } => TField::Set(Box::new(field_type(t))), SimplePattern::Dictof { key: k, value: v } => TField::Map(Box::new(field_type(k)), Box::new(field_type(v))), SimplePattern::Ref(r) => { let Ref { module: ModulePath(mp), name: n } = &**r; TField::Ref(mp.clone(), n.to_owned()) } } } pub fn render_field_type( ctxt: &ModuleContext, box_needed: bool, t: &TField, ) -> impl Emittable { match t { TField::Unit => seq!["()"], TField::Array(t) => seq!["std::vec::Vec<", render_field_type(ctxt, false, t), ">"], TField::Set(t) => seq!["preserves::value::Set<", render_field_type(ctxt, false, t), ">"], TField::Map(k, v) => seq!["preserves::value::Map", anglebrackets![render_field_type(ctxt, false, k), render_field_type(ctxt, false, v)]], TField::Ref(mp, n) => if box_needed { seq!["std::boxed::Box", anglebrackets![ctxt.render_ref(mp.clone(), n.to_owned())]] } else { seq![ctxt.render_ref(mp.clone(), n.to_owned())] }, TField::Base(n) => seq![n.to_owned()], } } pub fn render_recordlike_type( ctxt: &ModuleContext, 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(ctxt, !is_struct, d)] )).collect())], TSimple::Field(TField::Unit) => semi, TSimple::Field(t) => seq![parens![seq![ppub, render_field_type(ctxt, !is_struct, t)]], semi], }] } pub fn render_definition_type( ctxt: &ModuleContext, n: &str, t: &TDefinition, ) -> impl Emittable { seq!["#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone)]\n", match t { TDefinition::Union(items) => seq!["pub enum ", names::render_constructor(n), " ", braces( items.iter().map(|(n, d)| item(render_recordlike_type(ctxt, false, n, d))).collect())], TDefinition::Simple(s) => seq!["pub struct ", render_recordlike_type(ctxt, true, n, s)], }] }