preserves/implementations/rust/preserves-schema/src/compiler/parsers.rs

273 lines
13 KiB
Rust

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<Self, Self::Error> ",
block(body)]]])
});
}
fn construct(
ctxt: &FunctionContext,
ctorname: Item,
is_struct: bool,
ty: &TDefinition,
dest: Option<&str>,
body: &mut Vec<Item>,
) {
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<Item>, name: &str, expr: Item) {
body.push(item(seq!["let ", name.to_owned(), " = ", expr, ";"]))
}
fn push_let_mut(body: &mut Vec<Item>, 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<usize>,
body: &mut Vec<Item>,
) -> Option<String> {
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<String> = 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<usize>,
body: &mut Vec<Item>,
) -> (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<Item>,
) {
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<usize>,
body: &mut Vec<Item>,
) -> Option<String> {
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"),
}
}
}
}