//! Interpreter for instances of Preserves Schema Metaschema, for schema-directed dynamic //! parsing and unparsing of terms. use crate::gen::schema::*; use preserves::value::merge::merge2; use preserves::value::Map; use preserves::value::NestedValue; use preserves::value::Value; /// Represents an environment mapping schema module names to [Schema] instances. pub type Env = Map, Schema>; /// Context for a given interpretation of a [Schema]. #[derive(Debug)] pub struct Context<'a, V: NestedValue> { pub env: &'a Env, module: Vec, } #[derive(Debug)] enum DynField { Simple(V), Compound(Map), } impl<'a, V: NestedValue> Context<'a, V> { /// Construct a new [Context] with the given [Env]. pub fn new(env: &'a Env) -> Self { Context { env, module: Vec::new(), } } /// Parse `v` using the rule named `name` from the module at path `module` in `self.env`. /// Yields `Some(...)` if the parse succeeds, and `None` otherwise. pub fn dynamic_parse(&mut self, module: &Vec, name: &str, v: &V) -> Option { let old_module = (module.len() > 0).then(|| std::mem::replace(&mut self.module, module.clone())); let schema = self.env.get(&self.module); let definition = schema.and_then(|s| s.definitions.0.get(name)); let result = definition.and_then(|d| d.dynamic_parse(self, v)); if let Some(m) = old_module { self.module = m; } result } #[doc(hidden)] pub fn dynamic_unparse(&mut self, _module: &Vec, _name: &str, _w: &V) -> Option { panic!("Not yet implemented"); } } impl Definition { fn dynamic_parse(&self, ctxt: &mut Context, v: &V) -> Option { match self { Definition::Or { pattern_0, pattern_1, pattern_n, } => pattern_0 .dynamic_parse(ctxt, v) .or_else(|| pattern_1.dynamic_parse(ctxt, v)) .or_else(|| pattern_n.iter().find_map(|p| p.dynamic_parse(ctxt, v))), Definition::And { pattern_0, pattern_1, pattern_n, } => pattern_0 .dynamic_parse(ctxt, v) .and_then(|w0| { pattern_1.dynamic_parse(ctxt, v).and_then(|w1| { pattern_n.iter().fold(merge(w0, w1), |w, p| { w.and_then(|w| p.dynamic_parse(ctxt, v).and_then(|wn| merge(w, wn))) }) }) }) .map(|w| DynField::Compound(w).finish()), Definition::Pattern(p) => p.dynamic_parse(ctxt, v).map(|w| w.finish()), } } } impl NamedAlternative { fn dynamic_parse(&self, ctxt: &mut Context, v: &V) -> Option { self.pattern.dynamic_parse(ctxt, v).map(|w| { let mut r = Value::simple_record(&self.variant_label, 1); match w { DynField::Simple(field) => r.fields_vec_mut().push(field), DynField::Compound(fields) => { if fields.len() > 0 { r.fields_vec_mut().push(V::new(fields)) } } } r.finish().wrap() }) } } impl NamedPattern { fn dynamic_parse(&self, ctxt: &mut Context, v: &V) -> Option> { match self { NamedPattern::Named(b) => { let binding = &**b; binding .pattern .dynamic_parse(ctxt, v) .map(|w| w.to_map(Some(&binding.name))) } NamedPattern::Anonymous(b) => b.dynamic_parse(ctxt, v).map(|w| w.to_map(None)), } } } impl NamedSimplePattern { fn dynamic_parse(&self, ctxt: &mut Context, v: &V) -> Option> { match self { NamedSimplePattern::Named(b) => { let binding = &**b; binding .pattern .dynamic_parse(ctxt, v) .map(|w| DynField::Compound(w.to_map(Some(&binding.name)))) } NamedSimplePattern::Anonymous(b) => b.dynamic_parse(ctxt, v), } } } impl SimplePattern { fn dynamic_parse(&self, ctxt: &mut Context, v: &V) -> Option> { match self { SimplePattern::Any => Some(DynField::Simple(v.clone())), SimplePattern::Atom { atom_kind } => match &**atom_kind { AtomKind::Boolean => v.value().is_boolean().then(|| DynField::Simple(v.clone())), AtomKind::Double => v.value().is_double().then(|| DynField::Simple(v.clone())), AtomKind::SignedInteger => v .value() .is_signedinteger() .then(|| DynField::Simple(v.clone())), AtomKind::String => v.value().is_string().then(|| DynField::Simple(v.clone())), AtomKind::ByteString => v .value() .is_bytestring() .then(|| DynField::Simple(v.clone())), AtomKind::Symbol => v.value().is_symbol().then(|| DynField::Simple(v.clone())), }, SimplePattern::Embedded { .. } => { v.value().is_embedded().then(|| DynField::Simple(v.clone())) } SimplePattern::Lit { value } => (v == value).then(|| DynField::Compound(Map::new())), SimplePattern::Seqof { pattern } => v .value() .as_sequence() .and_then(|vs| { vs.iter() .map(|v| (**pattern).dynamic_parse(ctxt, v).map(|w| w.finish())) .collect::>>() }) .map(|ws| DynField::Simple(V::new(ws))), SimplePattern::Setof { pattern } => v .value() .as_set() .and_then(|vs| { vs.iter() .map(|v| (**pattern).dynamic_parse(ctxt, v).map(|w| w.finish())) .collect::>>() }) .map(|ws| DynField::Simple(V::new(ws))), SimplePattern::Dictof { key, value } => v .value() .as_dictionary() .and_then(|d| { d.iter() .map(|(k, v)| { (**key).dynamic_parse(ctxt, k).and_then(|kw| { (**value) .dynamic_parse(ctxt, v) .map(|vw| (kw.finish(), vw.finish())) }) }) .collect::>>() }) .map(|d| DynField::Simple(V::new(d))), SimplePattern::Ref(r) => ctxt .dynamic_parse(&r.module.0, &r.name, v) .map(DynField::Simple), } } } impl CompoundPattern { fn dynamic_parse(&self, ctxt: &mut Context, v: &V) -> Option> { match self { CompoundPattern::Rec { label, fields } => v.value().as_record(None).and_then(|r| { (**label).dynamic_parse(ctxt, r.label()).and_then(|lw| { (**fields) .dynamic_parse(ctxt, &V::new(r.fields().to_vec())) .and_then(|fsw| merge(lw, fsw)) }) }), CompoundPattern::Tuple { patterns } => v.value().as_sequence().and_then(|vs| { if vs.len() == patterns.len() { patterns .iter() .zip(vs) .fold(Some(Map::new()), |acc, (p, v)| { acc.and_then(|acc| p.dynamic_parse(ctxt, v).and_then(|w| merge(acc, w))) }) } else { None } }), CompoundPattern::TuplePrefix { fixed, variable } => { v.value().as_sequence().and_then(|vs| { if vs.len() >= fixed.len() { fixed .iter() .zip(vs) .fold(Some(Map::new()), |acc, (p, v)| { acc.and_then(|acc| { p.dynamic_parse(ctxt, v).and_then(|w| merge(acc, w)) }) }) .and_then(|fixed_ws| { let remainder = V::new(vs[fixed.len()..].to_vec()); (**variable).dynamic_parse(ctxt, &remainder).and_then( |variable_ws| merge(fixed_ws, variable_ws.unwrap_compound()), ) }) } else { None } }) } CompoundPattern::Dict { entries } => v.value().as_dictionary().and_then(|d| { (**entries).0.iter().fold(Some(Map::new()), |acc, (k, p)| { acc.and_then(|acc| { d.get(k).and_then(|v| { p.dynamic_parse(ctxt, v) .and_then(|w| merge(acc, w.unwrap_compound())) }) }) }) }), } } } impl Pattern { fn dynamic_parse(&self, ctxt: &mut Context, v: &V) -> Option> { match self { Pattern::SimplePattern(b) => (**b).dynamic_parse(ctxt, v), Pattern::CompoundPattern(b) => (**b).dynamic_parse(ctxt, v).map(DynField::Compound), } } } impl DynField { fn finish(self) -> V { match self { DynField::Simple(v) => v, DynField::Compound(v) => V::new(v), } } fn to_map(self, key: Option<&str>) -> Map { match self { DynField::Simple(v) => { let mut d = Map::new(); if let Some(k) = key { d.insert(V::symbol(k), v); } d } DynField::Compound(d) => d, } } fn unwrap_compound(self) -> Map { match self { DynField::Simple(_) => panic!("Cannot unwrap DynField::Simple to compound fields"), DynField::Compound(d) => d, } } } fn merge(a: Map, b: Map) -> Option> { merge2(V::new(a), V::new(b)).map(|d| { d.value_owned() .into_dictionary() .expect("merge to yield Dictionary") }) }