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, false, &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)), true, &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)), true, &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, is_struct: bool, 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(is_struct, fieldty, dest.unwrap())], ")"])), _ => body.push(item(seq!["Ok(", ctorname, " ", braces( ctxt.captures.iter().map( |c| item(seq![c.field_name.clone(), ": ", store_wrap(is_struct, &c.ty, &c.source_expr)])).collect()), ")"])), } } fn store_wrap(is_struct: bool, ty: &TField, expr: &str) -> String { match ty { TField::Unit | TField::Array(_) | TField::Set(_) | TField::Map(_, _) => expr.to_owned(), TField::Ref(_) => if is_struct { expr.to_owned() } else { format!("std::boxed::Box::new({})", expr) }, 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(", store_wrap(true, &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(", store_wrap(true, &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(", store_wrap(true, &field_type(&fs[0]).unwrap().unwrap(), &key_dest.unwrap()), ", ", store_wrap(true, &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_ty = field_type(&r.fields()[1]).unwrap().unwrap(); ctxt.capture(names::render_fieldname(r.fields()[0].value().as_symbol().unwrap()), capture_ty, dest.to_owned()); 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"), } } } }