2021-07-21 19:52:20 +00:00
|
|
|
use crate::*;
|
|
|
|
use crate::gen::schema::*;
|
|
|
|
use crate::syntax::block::Item;
|
|
|
|
use crate::syntax::block::escape_string;
|
|
|
|
use crate::syntax::block::escape_bytes;
|
|
|
|
use crate::syntax::block::constructors::*;
|
|
|
|
|
|
|
|
use preserves::value::AtomClass;
|
|
|
|
use preserves::value::CompoundClass;
|
|
|
|
use preserves::value::NestedValue;
|
|
|
|
use preserves::value::ValueClass;
|
|
|
|
|
|
|
|
use super::context::{ModuleContext, FunctionContext};
|
|
|
|
use super::names;
|
|
|
|
use super::types::*;
|
|
|
|
|
2021-08-12 19:28:24 +00:00
|
|
|
#[derive(Debug)]
|
2021-08-12 19:23:37 +00:00
|
|
|
pub struct ReaderPlugin;
|
|
|
|
|
|
|
|
impl compiler::Plugin for ReaderPlugin {
|
2021-08-12 19:28:24 +00:00
|
|
|
fn generate(&self, module_ctxt: &mut ModuleContext, definition_name: &str, definition: &Definition) {
|
2021-08-12 19:23:37 +00:00
|
|
|
if module_ctxt.mode.is_none() {
|
|
|
|
gen_definition_reader(module_ctxt, definition_name, definition)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-02 18:55:44 +00:00
|
|
|
#[derive(Clone)]
|
|
|
|
struct BoundaryTracker {
|
|
|
|
tracker_name: String,
|
|
|
|
item_expr: &'static str,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BoundaryTracker {
|
|
|
|
fn unwrap(
|
|
|
|
ctxt: &mut FunctionContext,
|
|
|
|
body: &mut Vec<Item>,
|
|
|
|
open_expr: &'static str,
|
|
|
|
e: Option<&BoundaryTracker>,
|
|
|
|
) -> Self {
|
|
|
|
match e {
|
|
|
|
None => Self::new(ctxt, body, open_expr, "_support::B::Item::SequenceValue"),
|
|
|
|
Some(b) => b.clone(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn new(
|
|
|
|
ctxt: &mut FunctionContext,
|
|
|
|
body: &mut Vec<Item>,
|
|
|
|
open_expr: &'static str,
|
|
|
|
item_expr: &'static str,
|
|
|
|
) -> Self {
|
|
|
|
let tracker_name = ctxt.gentempname();
|
|
|
|
body.push(item(open_expr));
|
|
|
|
body.push(item(seq!["let mut ", tracker_name.clone(), " = _support::B::Type::default();"]));
|
|
|
|
BoundaryTracker {
|
|
|
|
tracker_name,
|
|
|
|
item_expr,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn emit_boundary(&self, body: &mut Vec<Item>) {
|
|
|
|
body.push(item(seq![self.tracker_name.clone(), ".shift(Some(", self.item_expr, "));"]));
|
|
|
|
body.push(item(seq!["r.boundary(&", self.tracker_name.clone(), ")?;"]));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn emit_loop(&self, body: &mut Vec<Item>, inner: Vec<Item>) {
|
|
|
|
body.push(item(seq![
|
|
|
|
"while !r.close_compound", parens![
|
|
|
|
seq!["&mut ", self.tracker_name.clone()],
|
|
|
|
seq!["&", self.item_expr]], "? ",
|
|
|
|
block(inner)]))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-21 19:52:20 +00:00
|
|
|
pub fn gen_definition_reader(m: &mut ModuleContext, n: &str, d: &Definition) {
|
|
|
|
m.define_function(
|
|
|
|
n,
|
|
|
|
|mut ctxt| {
|
|
|
|
let mut body = vec![];
|
|
|
|
|
|
|
|
match d {
|
|
|
|
Definition::Or { pattern_0, pattern_1, pattern_n } => {
|
|
|
|
let mut ps = vec![&**pattern_0, &**pattern_1];
|
|
|
|
ps.extend(pattern_n);
|
|
|
|
ctxt.define_atom(&mut body, "_mark", item("r.mark()?"));
|
|
|
|
for NamedAlternative { variant_label: name, pattern: pat } in ps {
|
2021-07-21 20:34:02 +00:00
|
|
|
let fname = seq!["read_", names::render_fieldname(n), "_", names::render_fieldname(name)];
|
2021-07-21 19:52:20 +00:00
|
|
|
let ctorname = item(name![names::render_constructor(n), names::render_constructor(name)]);
|
|
|
|
ctxt.m.define_function(
|
|
|
|
&(n.to_owned() + "::" + name),
|
|
|
|
|mut ctxt| {
|
|
|
|
let mut body = Vec::new();
|
2021-08-02 18:55:44 +00:00
|
|
|
let dest = pattern_reader(&mut ctxt, pat, None, &mut body);
|
2021-07-21 19:52:20 +00:00
|
|
|
let dest = dest.as_ref().map(String::as_str);
|
|
|
|
construct(&ctxt, ctorname, false, &pattern_type(pat), dest, &mut body);
|
|
|
|
item(seq![
|
|
|
|
"fn ", fname.clone(), anglebrackets![
|
|
|
|
"'de",
|
|
|
|
"R: _support::Reader<'de, _Ptr, _Any>"],
|
|
|
|
"(r: &mut R) -> ",
|
|
|
|
"std::result::Result<", names::render_constructor(n), ", _support::ParseError> ",
|
|
|
|
block(body)])
|
|
|
|
});
|
|
|
|
body.push(item(seq![
|
|
|
|
"match ", fname, "(r) { ",
|
|
|
|
"Err(e) if e.is_conformance_error() => r.restore(&_mark)?, ",
|
|
|
|
"result => return result }"]));
|
|
|
|
}
|
|
|
|
body.push(item(seq![ctxt.err_code()]));
|
|
|
|
}
|
|
|
|
Definition::And { pattern_0, pattern_1, pattern_n } => {
|
|
|
|
let mut ps = vec![&**pattern_0, &**pattern_1];
|
2021-09-11 00:53:46 +00:00
|
|
|
let mut need_restore = false;
|
2021-07-21 19:52:20 +00:00
|
|
|
ps.extend(pattern_n);
|
2021-09-11 00:53:46 +00:00
|
|
|
ctxt.define_atom(&mut body, "_mark", item("r.mark()?"));
|
2021-07-21 19:52:20 +00:00
|
|
|
for e in &ps {
|
2021-09-11 00:53:46 +00:00
|
|
|
if need_restore {
|
|
|
|
body.push(item("r.restore(&_mark)?;"));
|
|
|
|
} else {
|
|
|
|
need_restore = true;
|
|
|
|
}
|
2021-08-02 18:55:44 +00:00
|
|
|
named_pattern_reader(&mut ctxt, e, None, &mut body);
|
2021-07-21 19:52:20 +00:00
|
|
|
}
|
|
|
|
construct(&ctxt, item(names::render_constructor(n)), true, &record_type(&ps), None, &mut body);
|
|
|
|
}
|
|
|
|
Definition::Pattern(p) => {
|
2021-08-02 18:55:44 +00:00
|
|
|
let dest = pattern_reader(&mut ctxt, p, None, &mut body);
|
2021-07-21 19:52:20 +00:00
|
|
|
let dest = dest.as_ref().map(String::as_str);
|
|
|
|
construct(&ctxt, item(names::render_constructor(n)), true, &pattern_type(p), dest, &mut body);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
item(seq![
|
|
|
|
"impl", anglebrackets!["'de", "R: _support::Reader<'de, _Ptr, _Any>"], " ",
|
|
|
|
"_support::Deserialize", anglebrackets!["'de", "_Ptr", "_Any", "R"], " ",
|
|
|
|
"for ", names::render_constructor(n), " ", block![
|
|
|
|
seq!["fn deserialize(r: &mut R) -> ",
|
|
|
|
"std::result::Result<Self, _support::ParseError> ",
|
|
|
|
block(body)]]])
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
fn construct(
|
|
|
|
ctxt: &FunctionContext,
|
|
|
|
ctorname: Item,
|
|
|
|
is_struct: bool,
|
|
|
|
ty: &TSimple,
|
|
|
|
dest: Option<&str>,
|
|
|
|
body: &mut Vec<Item>,
|
|
|
|
) {
|
|
|
|
match ty {
|
|
|
|
TSimple::Field(TField::Unit) =>
|
|
|
|
body.push(item(seq!["Ok(", ctorname, ")"])),
|
|
|
|
TSimple::Field(fieldty) =>
|
|
|
|
body.push(item(seq!["Ok(", ctorname, parens![store_wrap(is_struct, fieldty, dest.unwrap())], ")"])),
|
|
|
|
TSimple::Record(_) =>
|
|
|
|
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)
|
|
|
|
},
|
2021-09-12 16:28:29 +00:00
|
|
|
TField::Base(_) | TField::Any | TField::Embedded => expr.to_owned(),
|
2021-07-21 19:52:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn group_by<T, K, Key>(mut items: Vec<T>, mut key: Key) -> Vec<(K, Vec<T>)>
|
|
|
|
where
|
|
|
|
K: Ord + Clone,
|
|
|
|
Key: FnMut(&T) -> K,
|
|
|
|
{
|
|
|
|
let mut result = Vec::new();
|
|
|
|
let mut current_key: Option<K> = None;
|
|
|
|
let mut buf = Vec::new();
|
|
|
|
items.sort_by(|a, b| key(a).cmp(&key(b)));
|
|
|
|
for (k, v) in items.into_iter().map(|t| (key(&t), t)) {
|
|
|
|
match current_key.cmp(&Some(k.clone())) {
|
|
|
|
std::cmp::Ordering::Equal => (),
|
|
|
|
std::cmp::Ordering::Less |
|
|
|
|
std::cmp::Ordering::Greater => {
|
|
|
|
if let Some(k) = current_key {
|
|
|
|
result.push((k, std::mem::take(&mut buf)));
|
|
|
|
}
|
|
|
|
current_key = Some(k);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
buf.push(v)
|
|
|
|
}
|
|
|
|
if let Some(k) = current_key {
|
|
|
|
result.push((k.clone(), std::mem::take(&mut buf)));
|
|
|
|
}
|
|
|
|
result
|
|
|
|
}
|
|
|
|
|
|
|
|
type LiteralContinuation = Box<dyn FnOnce(&mut FunctionContext, &mut Vec<Item>) -> ()>;
|
|
|
|
type LiteralCases = Vec<(_Any, LiteralContinuation)>;
|
|
|
|
type LiteralSeqCases = Vec<(Vec<_Any>, LiteralContinuation)>;
|
|
|
|
|
|
|
|
fn read_expected_literal_seqs(
|
|
|
|
ctxt: &mut FunctionContext,
|
|
|
|
body: &mut Vec<Item>,
|
|
|
|
possibilities: LiteralSeqCases,
|
|
|
|
) {
|
|
|
|
let grouped = group_by(possibilities, |(vs, _f)| if vs.is_empty() {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(vs[0].clone())
|
|
|
|
});
|
|
|
|
let mut cases = Vec::new();
|
|
|
|
let mut nested: LiteralCases = Vec::new();
|
|
|
|
for (head, group) in grouped.into_iter() {
|
|
|
|
match head {
|
|
|
|
None => {
|
|
|
|
let mut inner = Vec::new();
|
|
|
|
group.into_iter().next().unwrap().1(ctxt, &mut inner);
|
|
|
|
cases.push(item(seq!["preserves::value::Token::End => ", block(inner)]));
|
|
|
|
},
|
|
|
|
Some(h) => {
|
|
|
|
let tails = group.into_iter().map(|(mut vs, f)| {
|
|
|
|
vs.remove(0);
|
|
|
|
(vs, f)
|
|
|
|
}).collect();
|
|
|
|
nested.push((h, Box::new(|ctxt: &mut FunctionContext, b: &'_ mut Vec<Item>| {
|
|
|
|
read_expected_literal_seqs(ctxt, b, tails)
|
|
|
|
})));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cases.extend(read_expected_literals_cases(ctxt, nested));
|
2021-08-02 18:55:44 +00:00
|
|
|
body.push(item(seq!["match r.next_token(true)? ", block(cases)]));
|
2021-07-21 19:52:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn read_expected_literals_cases(
|
|
|
|
ctxt: &mut FunctionContext,
|
|
|
|
possibilities: LiteralCases,
|
|
|
|
) -> Vec<Item> {
|
|
|
|
let grouped = group_by(possibilities, |(v, _f)| v.value_class());
|
|
|
|
let mut cases = grouped.into_iter().map(|(n, group)| {
|
|
|
|
match n {
|
|
|
|
ValueClass::Atomic(cls) => {
|
|
|
|
let mut subcases = Vec::new();
|
|
|
|
for p in group {
|
|
|
|
let mut inner = Vec::new();
|
|
|
|
p.1(ctxt, &mut inner);
|
|
|
|
subcases.push(item(seq![
|
|
|
|
format!("preserves::value::Value::{:?}(w)", cls),
|
|
|
|
match cls {
|
|
|
|
AtomClass::Boolean => match p.0.value().to_boolean().unwrap() {
|
|
|
|
true => " if *w".to_owned(),
|
|
|
|
false => " if !*w".to_owned(),
|
|
|
|
},
|
|
|
|
AtomClass::Float |
|
|
|
|
AtomClass::Double =>
|
|
|
|
format!(" if w.0 == {:?}", p.0),
|
|
|
|
AtomClass::SignedInteger =>
|
|
|
|
format!(" if *w == ({:?}).into()", p.0),
|
|
|
|
AtomClass::String =>
|
|
|
|
format!(" if w == {}", escape_string(p.0.value().to_string().unwrap())),
|
|
|
|
AtomClass::ByteString =>
|
|
|
|
format!(" if w == {}", escape_bytes(p.0.value().to_bytestring().unwrap())),
|
|
|
|
AtomClass::Symbol =>
|
|
|
|
format!(" if w == {}", escape_string(p.0.value().to_symbol().unwrap())),
|
|
|
|
},
|
|
|
|
" => ",
|
|
|
|
block(inner)]));
|
|
|
|
}
|
|
|
|
subcases.push(item(seq!["_ => return ", ctxt.err_code(), "?,"]));
|
|
|
|
item(seq!["preserves::value::Token::Atom(v) => match v.value() ", block(subcases)])
|
|
|
|
}
|
|
|
|
ValueClass::Compound(CompoundClass::Record) => {
|
|
|
|
let mut subcases = Vec::new();
|
|
|
|
read_expected_literal_seqs(ctxt, &mut subcases, group.into_iter().map(|(v, f)| {
|
|
|
|
let r = v.value().to_record(None).unwrap();
|
|
|
|
(r.0.clone(), f)
|
|
|
|
}).collect());
|
|
|
|
item(seq![
|
|
|
|
"preserves::value::Token::Compound(preserves::value::CompoundClass::Record) => ",
|
|
|
|
block(subcases)])
|
|
|
|
}
|
|
|
|
ValueClass::Compound(CompoundClass::Sequence) => {
|
|
|
|
let mut subcases = Vec::new();
|
|
|
|
read_expected_literal_seqs(ctxt, &mut subcases, group.into_iter().map(|(v, f)| {
|
|
|
|
let s = v.value().to_sequence().unwrap().clone();
|
|
|
|
(s, f)
|
|
|
|
}).collect());
|
|
|
|
item(seq![
|
|
|
|
"preserves::value::Token::Compound(preserves::value::CompoundClass::Sequence) => ",
|
|
|
|
block(subcases)])
|
|
|
|
}
|
|
|
|
ValueClass::Compound(CompoundClass::Set) => {
|
|
|
|
panic!("Sets in literal constants in Schema not yet supported");
|
|
|
|
}
|
|
|
|
ValueClass::Compound(CompoundClass::Dictionary) => {
|
|
|
|
panic!("Dictionaries in literal constants in Schema not yet supported");
|
|
|
|
}
|
|
|
|
ValueClass::Embedded => {
|
|
|
|
panic!("Embedded values in literal constants in Schema not yet supported");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}).collect::<Vec<_>>();
|
|
|
|
cases.push(item(seq!["_ => return ", ctxt.err_code(), "?,"]));
|
|
|
|
cases
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_expected_literals(
|
|
|
|
ctxt: &mut FunctionContext,
|
|
|
|
body: &mut Vec<Item>,
|
|
|
|
possibilities: LiteralCases,
|
|
|
|
) {
|
|
|
|
let cases = read_expected_literals_cases(ctxt, possibilities);
|
2021-08-02 18:55:44 +00:00
|
|
|
body.push(item(seq!["match r.next_token(true)? ", block(cases)]));
|
2021-07-21 19:52:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn simple_pattern_reader(
|
|
|
|
ctxt: &mut FunctionContext,
|
|
|
|
p: &SimplePattern,
|
2021-08-02 18:55:44 +00:00
|
|
|
boundary_tracker: Option<&BoundaryTracker>,
|
2021-07-21 19:52:20 +00:00
|
|
|
body: &mut Vec<Item>,
|
|
|
|
) -> String {
|
|
|
|
let dest = ctxt.gentempname();
|
|
|
|
match p {
|
|
|
|
SimplePattern::Any => {
|
2021-08-02 18:55:44 +00:00
|
|
|
ctxt.define_atom(body, &dest, item("r.demand_next(true)?"));
|
2021-07-21 19:52:20 +00:00
|
|
|
dest
|
|
|
|
},
|
|
|
|
SimplePattern::Atom { atom_kind: k } => {
|
|
|
|
let reader = match &**k {
|
|
|
|
AtomKind::Boolean => "r.next_boolean()?",
|
|
|
|
AtomKind::Float => "r.next_float()?",
|
|
|
|
AtomKind::Double => "r.next_double()?",
|
|
|
|
AtomKind::SignedInteger => "r.next_signedinteger()?",
|
|
|
|
AtomKind::String => "r.next_str()?.into_owned()",
|
|
|
|
AtomKind::ByteString => "r.next_bytestring()?.into_owned()",
|
|
|
|
AtomKind::Symbol => "r.next_symbol()?.into_owned()",
|
|
|
|
};
|
|
|
|
ctxt.define_atom(body, &dest, item(reader.to_owned()));
|
|
|
|
dest
|
|
|
|
},
|
|
|
|
SimplePattern::Embedded { .. } => {
|
2021-08-02 18:55:44 +00:00
|
|
|
// TODO: Is this right? If so, why doesn't it expect *two* Embedded tags in a row??
|
2021-07-21 19:52:20 +00:00
|
|
|
body.push(item("r.open_embedded()?;"));
|
2021-08-02 18:55:44 +00:00
|
|
|
ctxt.define_atom(body, &dest, item("r.demand_next(true)?.value().to_embedded()?.clone()"));
|
2021-07-21 19:52:20 +00:00
|
|
|
body.push(item("r.close_embedded()?;"));
|
|
|
|
dest
|
|
|
|
},
|
|
|
|
SimplePattern::Lit { value } => {
|
|
|
|
let f = Box::new(|_ctxt: &mut FunctionContext, _: &'_ mut Vec<Item>| ());
|
|
|
|
read_expected_literals(ctxt, body, vec![(value.clone(), f)]);
|
|
|
|
ctxt.define_atom(body, &dest, item("()"));
|
|
|
|
dest
|
|
|
|
},
|
|
|
|
SimplePattern::Seqof { pattern } => {
|
2021-09-11 00:53:32 +00:00
|
|
|
let compound_dest = ctxt.gentempname();
|
|
|
|
ctxt.with_definite_mode(|ctxt| {
|
|
|
|
let boundary_tracker = BoundaryTracker::unwrap(
|
|
|
|
ctxt, body, "r.open_sequence()?;", boundary_tracker);
|
|
|
|
let mut inner = Vec::new();
|
|
|
|
boundary_tracker.emit_boundary(&mut inner);
|
|
|
|
let item_dest = simple_pattern_reader(ctxt, pattern, None, &mut inner);
|
|
|
|
inner.push(item(seq![compound_dest.to_owned(), ".push(",
|
|
|
|
store_wrap(true, &field_type(pattern), &item_dest), ");"]));
|
|
|
|
ctxt.declare_compound(body, &compound_dest, item("std::vec::Vec::new()"));
|
|
|
|
boundary_tracker.emit_loop(body, inner);
|
|
|
|
});
|
|
|
|
ctxt.define_atom(body, &dest, item(compound_dest));
|
2021-07-21 19:52:20 +00:00
|
|
|
dest
|
|
|
|
},
|
|
|
|
SimplePattern::Setof { pattern } => {
|
2021-09-11 00:53:32 +00:00
|
|
|
let compound_dest = ctxt.gentempname();
|
|
|
|
ctxt.with_definite_mode(|ctxt| {
|
|
|
|
let boundary_tracker = BoundaryTracker::new(
|
|
|
|
ctxt, body, "r.open_set()?;", "_support::B::Item::SetValue");
|
|
|
|
let mut inner = Vec::new();
|
|
|
|
boundary_tracker.emit_boundary(&mut inner);
|
|
|
|
let item_dest = simple_pattern_reader(ctxt, pattern, None, &mut inner);
|
|
|
|
inner.push(item(seq![compound_dest.to_owned(), ".insert(",
|
|
|
|
store_wrap(true, &field_type(pattern), &item_dest), ");"]));
|
|
|
|
ctxt.declare_compound(body, &compound_dest, item("preserves::value::Set::new()"));
|
|
|
|
boundary_tracker.emit_loop(body, inner);
|
|
|
|
});
|
|
|
|
ctxt.define_atom(body, &dest, item(compound_dest));
|
2021-07-21 19:52:20 +00:00
|
|
|
dest
|
|
|
|
},
|
|
|
|
SimplePattern::Dictof { key, value } => {
|
2021-09-11 00:53:32 +00:00
|
|
|
let compound_dest = ctxt.gentempname();
|
|
|
|
ctxt.with_definite_mode(|ctxt| {
|
|
|
|
let mut boundary_tracker = BoundaryTracker::new(
|
|
|
|
ctxt, body, "r.open_dictionary()?;", "_support::B::Item::DictionaryKey");
|
|
|
|
let mut inner = Vec::new();
|
|
|
|
boundary_tracker.emit_boundary(&mut inner);
|
|
|
|
let key_dest = simple_pattern_reader(ctxt, key, None, &mut inner);
|
|
|
|
boundary_tracker.item_expr = "_support::B::Item::DictionaryValue";
|
|
|
|
boundary_tracker.emit_boundary(&mut inner);
|
|
|
|
let value_dest = simple_pattern_reader(ctxt, value, None, &mut inner);
|
|
|
|
inner.push(item(seq![
|
|
|
|
compound_dest.to_owned(), ".insert(",
|
|
|
|
store_wrap(true, &field_type(key), &key_dest), ", ",
|
|
|
|
store_wrap(true, &field_type(value), &value_dest), ");"]));
|
|
|
|
ctxt.declare_compound(body, &compound_dest, item("preserves::value::Map::new()"));
|
|
|
|
boundary_tracker.item_expr = "_support::B::Item::DictionaryKey";
|
|
|
|
boundary_tracker.emit_loop(body, inner);
|
|
|
|
});
|
|
|
|
ctxt.define_atom(body, &dest, item(compound_dest));
|
2021-07-21 19:52:20 +00:00
|
|
|
dest
|
|
|
|
},
|
|
|
|
SimplePattern::Ref(r) => {
|
|
|
|
let tf = name![ctxt.m.render_ref(&**r), "deserialize"];
|
|
|
|
ctxt.define_atom(body, &dest, item(seq![tf, "(r)?"]));
|
|
|
|
dest
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn named_pattern_reader(
|
|
|
|
ctxt: &mut FunctionContext,
|
|
|
|
p: &NamedPattern,
|
2021-08-02 18:55:44 +00:00
|
|
|
boundary_tracker: Option<&BoundaryTracker>,
|
2021-07-21 19:52:20 +00:00
|
|
|
body: &mut Vec<Item>,
|
|
|
|
) {
|
|
|
|
match p {
|
|
|
|
NamedPattern::Anonymous(p) => {
|
2021-08-02 18:55:44 +00:00
|
|
|
pattern_reader(ctxt, p, boundary_tracker, body);
|
2021-07-21 19:52:20 +00:00
|
|
|
},
|
|
|
|
NamedPattern::Named(b) => {
|
|
|
|
let Binding { name, pattern} = &**b;
|
2021-08-02 18:55:44 +00:00
|
|
|
let dest = simple_pattern_reader(ctxt, pattern, boundary_tracker, body);
|
2021-07-21 19:52:20 +00:00
|
|
|
let capture_ty = field_type(pattern);
|
|
|
|
ctxt.capture(names::render_fieldname(name), capture_ty, dest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn pattern_reader(
|
|
|
|
ctxt: &mut FunctionContext,
|
|
|
|
p: &Pattern,
|
2021-08-02 18:55:44 +00:00
|
|
|
boundary_tracker: Option<&BoundaryTracker>,
|
2021-07-21 19:52:20 +00:00
|
|
|
body: &mut Vec<Item>,
|
|
|
|
) -> Option<String> {
|
|
|
|
match p {
|
|
|
|
Pattern::SimplePattern(s) =>
|
2021-08-02 18:55:44 +00:00
|
|
|
Some(simple_pattern_reader(ctxt, s, boundary_tracker, body)),
|
2021-07-21 19:52:20 +00:00
|
|
|
Pattern::CompoundPattern(c) => {
|
|
|
|
match &**c {
|
|
|
|
CompoundPattern::Rec { label, fields } => {
|
2021-08-02 18:55:44 +00:00
|
|
|
let mut boundary_tracker = BoundaryTracker::new(
|
|
|
|
ctxt, body, "r.open_record(None)?;", "_support::B::Item::RecordLabel");
|
|
|
|
boundary_tracker.emit_boundary(body);
|
|
|
|
boundary_tracker.item_expr = "_support::B::Item::RecordField";
|
|
|
|
named_pattern_reader(ctxt, &**label, None, body);
|
|
|
|
named_pattern_reader(ctxt, &**fields, Some(&boundary_tracker), body);
|
2021-07-21 19:52:20 +00:00
|
|
|
},
|
|
|
|
CompoundPattern::Tuple { patterns } => {
|
2021-08-02 18:55:44 +00:00
|
|
|
let boundary_tracker = BoundaryTracker::unwrap(
|
|
|
|
ctxt, body, "r.open_sequence()?;", boundary_tracker);
|
|
|
|
for p in patterns {
|
|
|
|
boundary_tracker.emit_boundary(body);
|
|
|
|
named_pattern_reader(ctxt, p, None, body);
|
2021-07-21 19:52:20 +00:00
|
|
|
}
|
2021-08-02 18:55:44 +00:00
|
|
|
body.push(item(seq!["r.ensure_complete", parens![
|
|
|
|
boundary_tracker.tracker_name.clone(),
|
|
|
|
seq!["&", boundary_tracker.item_expr]], "?;"]));
|
2021-07-21 19:52:20 +00:00
|
|
|
},
|
|
|
|
CompoundPattern::TuplePrefix { fixed, variable } => {
|
2021-08-02 18:55:44 +00:00
|
|
|
let boundary_tracker = BoundaryTracker::unwrap(
|
|
|
|
ctxt, body, "r.open_sequence()?;", boundary_tracker);
|
|
|
|
for p in fixed {
|
|
|
|
boundary_tracker.emit_boundary(body);
|
|
|
|
named_pattern_reader(ctxt, p, None, body);
|
2021-07-21 19:52:20 +00:00
|
|
|
}
|
2021-08-02 18:55:44 +00:00
|
|
|
named_pattern_reader(ctxt, &promote(variable), Some(&boundary_tracker), body);
|
2021-07-21 19:52:20 +00:00
|
|
|
},
|
|
|
|
CompoundPattern::Dict { entries } => {
|
2021-08-02 18:55:44 +00:00
|
|
|
let boundary_tracker = BoundaryTracker::new(
|
|
|
|
ctxt, body, "r.open_dictionary()?;", "_support::B::Item::DictionaryKey");
|
2021-07-21 19:52:20 +00:00
|
|
|
let mut inner = Vec::new();
|
2021-08-02 18:55:44 +00:00
|
|
|
boundary_tracker.emit_boundary(&mut inner);
|
|
|
|
let mut val_boundary_tracker = boundary_tracker.clone();
|
|
|
|
val_boundary_tracker.item_expr = "_support::B::Item::DictionaryValue";
|
2021-07-21 19:52:20 +00:00
|
|
|
body.extend(ctxt.with_indefinite_mode(|ctxt| {
|
|
|
|
read_expected_literals(ctxt, &mut inner, entries.0.iter().map(move |(key_lit, value_pat)| {
|
|
|
|
let value_pat = value_pat.clone();
|
2021-08-02 18:55:44 +00:00
|
|
|
let val_boundary_tracker = val_boundary_tracker.clone();
|
2021-07-21 19:52:20 +00:00
|
|
|
let f: LiteralContinuation = Box::new(
|
|
|
|
move |ctxt: &mut FunctionContext, innerinner: &mut Vec<Item>| {
|
2021-08-02 18:55:44 +00:00
|
|
|
val_boundary_tracker.emit_boundary(innerinner);
|
|
|
|
named_pattern_reader(ctxt, &promote(&value_pat), None, innerinner);
|
2021-07-21 19:52:20 +00:00
|
|
|
innerinner.push(item("continue;"));
|
|
|
|
});
|
|
|
|
(key_lit.clone(), f)
|
|
|
|
}).collect());
|
|
|
|
}));
|
2021-08-02 18:55:44 +00:00
|
|
|
boundary_tracker.emit_loop(body, inner);
|
2021-07-21 19:52:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|