2021-06-29 20:32:35 +00:00
|
|
|
use crate::gen::schema::*;
|
2021-06-29 14:54:29 +00:00
|
|
|
use crate::syntax::block::constructors::*;
|
2023-07-21 16:15:30 +00:00
|
|
|
use crate::syntax::block::{escape_string, Emittable, Item};
|
|
|
|
use crate::*;
|
2021-06-29 14:54:29 +00:00
|
|
|
|
|
|
|
use std::cell::Cell;
|
|
|
|
use std::rc::Rc;
|
|
|
|
|
2023-07-21 16:15:30 +00:00
|
|
|
use super::context::{FunctionContext, ModuleContext, ModuleContextMode};
|
2021-06-29 14:54:29 +00:00
|
|
|
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 UnparserPlugin;
|
|
|
|
|
|
|
|
impl compiler::Plugin for UnparserPlugin {
|
2023-07-21 16:15:30 +00:00
|
|
|
fn generate_definition(
|
|
|
|
&self,
|
|
|
|
module_ctxt: &mut ModuleContext,
|
|
|
|
definition_name: &str,
|
|
|
|
definition: &Definition,
|
|
|
|
) {
|
2021-09-15 08:43:31 +00:00
|
|
|
if let ModuleContextMode::TargetGeneric = module_ctxt.mode {
|
2021-08-12 19:23:37 +00:00
|
|
|
gen_definition_unparser(module_ctxt, definition_name, definition)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-29 14:54:29 +00:00
|
|
|
type ValueSource = Option<String>;
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
struct FieldsSink {
|
|
|
|
finish: Item,
|
|
|
|
vec_expr: Item,
|
|
|
|
body: Vec<Item>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
enum ValueSink {
|
|
|
|
Normal,
|
|
|
|
Fields(Rc<Cell<Option<FieldsSink>>>),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::fmt::Debug for ValueSink {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
|
|
|
match self {
|
|
|
|
ValueSink::Normal => write!(f, "ValueSink::Normal"),
|
|
|
|
ValueSink::Fields(_) => write!(f, "ValueSink::Normal"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct ValueContext {
|
|
|
|
src: ValueSource,
|
|
|
|
sink: ValueSink,
|
|
|
|
is_struct: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
fn normal_none(is_struct: bool) -> ValueContext {
|
2023-07-21 16:15:30 +00:00
|
|
|
ValueContext {
|
|
|
|
src: None,
|
|
|
|
sink: ValueSink::Normal,
|
|
|
|
is_struct,
|
|
|
|
}
|
2021-06-29 14:54:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn normal_src(src: String, is_struct: bool) -> ValueContext {
|
2023-07-21 16:15:30 +00:00
|
|
|
ValueContext {
|
|
|
|
src: Some(src),
|
|
|
|
sink: ValueSink::Normal,
|
|
|
|
is_struct,
|
|
|
|
}
|
2021-06-29 14:54:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn gen_definition_unparser(m: &mut ModuleContext, n: &str, d: &Definition) {
|
2023-01-28 21:38:14 +00:00
|
|
|
let ty = definition_type(&m.module_path, Purpose::Codegen, n, d);
|
2021-09-15 08:43:31 +00:00
|
|
|
|
2023-07-21 16:15:30 +00:00
|
|
|
m.define_function(n, |mut ctxt| {
|
|
|
|
let mut body = vec![];
|
2021-06-29 14:54:29 +00:00
|
|
|
|
2023-07-21 16:15:30 +00:00
|
|
|
match d {
|
|
|
|
Definition::Or {
|
|
|
|
pattern_0,
|
|
|
|
pattern_1,
|
|
|
|
pattern_n,
|
|
|
|
} => {
|
|
|
|
let mut ps = vec![&**pattern_0, &**pattern_1];
|
|
|
|
ps.extend(pattern_n);
|
|
|
|
body.push(item(seq![
|
|
|
|
"match self ",
|
|
|
|
codeblock(
|
|
|
|
ps.iter()
|
|
|
|
.map(
|
|
|
|
|NamedAlternative {
|
|
|
|
variant_label: name,
|
|
|
|
pattern: pat,
|
|
|
|
}| ctxt.branch(|ctxt| {
|
|
|
|
let ctorname = item(name![
|
|
|
|
names::render_constructor(n),
|
|
|
|
names::render_constructor(name)
|
|
|
|
]);
|
|
|
|
let (patpat, vc) =
|
|
|
|
destruct(ctxt, ctorname, false, &pattern_type(pat));
|
|
|
|
item(seq![
|
|
|
|
patpat,
|
|
|
|
" => ",
|
|
|
|
pattern_unparser(ctxt, pat, &vc),
|
|
|
|
","
|
|
|
|
])
|
|
|
|
})
|
|
|
|
)
|
|
|
|
.collect()
|
|
|
|
)
|
|
|
|
]));
|
|
|
|
}
|
|
|
|
Definition::And {
|
|
|
|
pattern_0,
|
|
|
|
pattern_1,
|
|
|
|
pattern_n,
|
|
|
|
} => {
|
|
|
|
let mut ps = vec![&**pattern_0, &**pattern_1];
|
|
|
|
ps.extend(pattern_n);
|
|
|
|
let (patpat, vc) = destruct(
|
|
|
|
&mut ctxt,
|
|
|
|
item(names::render_constructor(n)),
|
|
|
|
true,
|
|
|
|
&record_type(&ps),
|
|
|
|
);
|
|
|
|
body.push(item(seq!["let ", patpat, " = self;"]));
|
|
|
|
body.push(item(seq![
|
|
|
|
"preserves::value::merge(vec!",
|
|
|
|
brackets(
|
|
|
|
ps.iter()
|
|
|
|
.map(|p| named_pattern_unparser(&mut ctxt, p, &vc))
|
|
|
|
.collect()
|
|
|
|
),
|
|
|
|
").expect",
|
|
|
|
parens![escape_string(
|
|
|
|
&("merge of ".to_owned() + &ctxt.fully_qualified_error_context())
|
|
|
|
)]
|
|
|
|
]));
|
2021-06-29 14:54:29 +00:00
|
|
|
}
|
2023-07-21 16:15:30 +00:00
|
|
|
Definition::Pattern(p) => {
|
|
|
|
let (patpat, vc) = destruct(
|
|
|
|
&mut ctxt,
|
|
|
|
item(names::render_constructor(n)),
|
|
|
|
true,
|
|
|
|
&pattern_type(p),
|
|
|
|
);
|
|
|
|
body.push(item(seq!["let ", patpat, " = self;"]));
|
|
|
|
body.push(pattern_unparser(&mut ctxt, p, &vc));
|
|
|
|
}
|
|
|
|
}
|
2021-06-29 14:54:29 +00:00
|
|
|
|
2023-07-21 16:15:30 +00:00
|
|
|
item(seq![
|
|
|
|
"impl",
|
|
|
|
ctxt.m.parse_unparse_generic_decls(&ty),
|
|
|
|
" _support::Unparse",
|
|
|
|
anglebrackets!["_L", ctxt.m.any_type()],
|
|
|
|
" for ",
|
|
|
|
names::render_constructor(n),
|
|
|
|
ty.generic_arg(ctxt.m),
|
|
|
|
" ",
|
|
|
|
codeblock![seq![
|
|
|
|
"fn unparse(&self, _ctxt: _L) -> ",
|
|
|
|
ctxt.m.any_type(),
|
|
|
|
" ",
|
|
|
|
codeblock(body)
|
|
|
|
]]
|
|
|
|
])
|
|
|
|
});
|
2021-06-29 14:54:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn destruct(
|
|
|
|
ctxt: &mut FunctionContext,
|
|
|
|
ctorname: Item,
|
|
|
|
is_struct: bool,
|
|
|
|
ty: &TSimple,
|
|
|
|
) -> (impl Emittable, ValueContext) {
|
|
|
|
match ty {
|
|
|
|
TSimple::Field(TField::Unit) => (seq![ctorname], normal_none(is_struct)),
|
|
|
|
TSimple::Field(_) => {
|
|
|
|
let src = ctxt.gentempname();
|
2023-07-21 16:15:30 +00:00
|
|
|
(
|
|
|
|
seq![ctorname, parens![src.to_owned()]],
|
|
|
|
normal_src(src, is_struct),
|
|
|
|
)
|
2021-06-29 14:54:29 +00:00
|
|
|
}
|
|
|
|
TSimple::Record(TRecord(fs)) => {
|
|
|
|
for (fname, fty) in fs {
|
|
|
|
let fsrc = ctxt.gentempname();
|
|
|
|
ctxt.capture(names::render_fieldname(fname), fty.clone(), fsrc);
|
|
|
|
}
|
2023-07-21 16:15:30 +00:00
|
|
|
(
|
|
|
|
seq![
|
|
|
|
ctorname,
|
|
|
|
" ",
|
|
|
|
braces(
|
|
|
|
ctxt.captures
|
|
|
|
.iter()
|
|
|
|
.map(|c| item(seq![c.field_name.clone(), ": ", c.source_expr.clone()]))
|
|
|
|
.collect()
|
|
|
|
)
|
|
|
|
],
|
|
|
|
normal_none(is_struct),
|
|
|
|
)
|
2021-06-29 14:54:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn simple_pattern_unparser(
|
|
|
|
ctxt: &mut FunctionContext,
|
|
|
|
p: &SimplePattern,
|
|
|
|
vc: &ValueContext,
|
|
|
|
) -> Item {
|
|
|
|
let src = &vc.src;
|
|
|
|
match p {
|
2023-07-21 16:15:30 +00:00
|
|
|
SimplePattern::Any => item(seq![src.as_ref().unwrap().to_owned(), ".clone()"]),
|
|
|
|
SimplePattern::Atom { atom_kind: k } => match &**k {
|
|
|
|
AtomKind::Symbol => item(seq![
|
|
|
|
"preserves::value::Value::symbol(",
|
|
|
|
src.as_ref().unwrap().to_owned(),
|
|
|
|
").wrap()"
|
|
|
|
]),
|
|
|
|
AtomKind::ByteString => item(seq![
|
|
|
|
"preserves::value::Value::ByteString(",
|
|
|
|
src.as_ref().unwrap().to_owned(),
|
|
|
|
".clone()).wrap()"
|
|
|
|
]),
|
|
|
|
_ => item(seq![
|
|
|
|
"preserves::value::Value::from(",
|
|
|
|
src.as_ref().unwrap().to_owned(),
|
|
|
|
").wrap()"
|
|
|
|
]),
|
|
|
|
},
|
|
|
|
SimplePattern::Embedded { .. } => item(seq![
|
|
|
|
"preserves::value::Value::Embedded(",
|
|
|
|
src.as_ref().unwrap().to_owned(),
|
|
|
|
".clone()).wrap()"
|
|
|
|
]),
|
|
|
|
SimplePattern::Lit { value } => {
|
|
|
|
item(seq![parens![ctxt.m.define_literal(value)], ".clone()"])
|
2021-06-29 14:54:29 +00:00
|
|
|
}
|
|
|
|
SimplePattern::Seqof { pattern } => {
|
|
|
|
let mut fields_sink = sequenceify(ctxt, vc);
|
|
|
|
let tmp = ctxt.gentempname();
|
|
|
|
fields_sink.body.push(item(seq![
|
2023-07-21 16:15:30 +00:00
|
|
|
"for ",
|
|
|
|
tmp.to_owned(),
|
|
|
|
" in ",
|
|
|
|
src.as_ref().unwrap().to_owned(),
|
|
|
|
" ",
|
|
|
|
codeblock![seq![
|
|
|
|
fields_sink.vec_expr.clone(),
|
|
|
|
".push(",
|
|
|
|
simple_pattern_unparser(ctxt, pattern, &normal_src(tmp, true)),
|
|
|
|
");"
|
|
|
|
]]
|
|
|
|
]));
|
2021-06-29 14:54:29 +00:00
|
|
|
finish(fields_sink)
|
|
|
|
}
|
|
|
|
SimplePattern::Setof { pattern } => {
|
|
|
|
let tmp = ctxt.gentempname();
|
2023-07-21 16:15:30 +00:00
|
|
|
item(seq![
|
|
|
|
"preserves::value::Value::Set(",
|
|
|
|
src.as_ref().unwrap().to_owned(),
|
|
|
|
".iter().map(|",
|
|
|
|
tmp.to_owned(),
|
|
|
|
"| ",
|
|
|
|
simple_pattern_unparser(ctxt, pattern, &normal_src(tmp, true)),
|
|
|
|
").collect()).wrap()"
|
|
|
|
])
|
2021-06-29 14:54:29 +00:00
|
|
|
}
|
|
|
|
SimplePattern::Dictof { key, value } => {
|
|
|
|
let tmp_key = ctxt.gentempname();
|
|
|
|
let tmp_value = ctxt.gentempname();
|
2023-07-21 16:15:30 +00:00
|
|
|
item(seq![
|
|
|
|
"preserves::value::Value::Dictionary(",
|
|
|
|
src.as_ref().unwrap().to_owned(),
|
|
|
|
".iter().map(|(",
|
|
|
|
tmp_key.to_owned(),
|
|
|
|
", ",
|
|
|
|
tmp_value.to_owned(),
|
|
|
|
")| ",
|
|
|
|
parens![
|
|
|
|
simple_pattern_unparser(ctxt, key, &normal_src(tmp_key, true)),
|
|
|
|
simple_pattern_unparser(ctxt, value, &normal_src(tmp_value, true))
|
|
|
|
],
|
|
|
|
").collect()).wrap()"
|
|
|
|
])
|
2021-06-29 14:54:29 +00:00
|
|
|
}
|
2023-07-21 16:15:30 +00:00
|
|
|
SimplePattern::Ref(_r) => item(seq![
|
|
|
|
src.as_ref().unwrap().to_owned(),
|
|
|
|
if vc.is_struct { "" } else { ".as_ref()" },
|
|
|
|
".unparse(_ctxt)"
|
|
|
|
]),
|
2021-06-29 14:54:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-21 16:15:30 +00:00
|
|
|
fn named_pattern_unparser(ctxt: &mut FunctionContext, p: &NamedPattern, vc: &ValueContext) -> Item {
|
2021-06-29 14:54:29 +00:00
|
|
|
match p {
|
2023-07-21 16:15:30 +00:00
|
|
|
NamedPattern::Anonymous(p) => pattern_unparser(ctxt, p, vc),
|
2021-06-29 14:54:29 +00:00
|
|
|
NamedPattern::Named(b) => {
|
2023-07-21 16:15:30 +00:00
|
|
|
let Binding { name, pattern } = &**b;
|
|
|
|
let src = ctxt
|
|
|
|
.lookup_capture(&names::render_fieldname(name))
|
|
|
|
.source_expr
|
|
|
|
.to_owned();
|
|
|
|
simple_pattern_unparser(
|
|
|
|
ctxt,
|
|
|
|
pattern,
|
|
|
|
&ValueContext {
|
|
|
|
src: Some(src),
|
|
|
|
sink: vc.sink.clone(),
|
|
|
|
is_struct: vc.is_struct,
|
|
|
|
},
|
|
|
|
)
|
2021-06-29 14:54:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-21 16:15:30 +00:00
|
|
|
fn pattern_unparser(ctxt: &mut FunctionContext, p: &Pattern, vc: &ValueContext) -> Item {
|
2021-06-29 14:54:29 +00:00
|
|
|
match p {
|
2023-07-21 16:15:30 +00:00
|
|
|
Pattern::SimplePattern(s) => simple_pattern_unparser(ctxt, s, vc),
|
|
|
|
Pattern::CompoundPattern(c) => match &**c {
|
|
|
|
CompoundPattern::Rec { label, fields } => {
|
|
|
|
let rtmp = ctxt.gentempname();
|
|
|
|
let mut body = Vec::new();
|
|
|
|
let init_expr = item(seq![
|
|
|
|
"preserves::value::Record(vec![",
|
|
|
|
named_pattern_unparser(ctxt, label, &normal_none(vc.is_struct)),
|
|
|
|
"])"
|
|
|
|
]);
|
|
|
|
ctxt.declare_compound(&mut body, &rtmp, init_expr);
|
|
|
|
named_pattern_unparser(
|
|
|
|
ctxt,
|
|
|
|
fields,
|
|
|
|
&ValueContext {
|
2021-06-29 14:54:29 +00:00
|
|
|
src: None,
|
|
|
|
sink: ValueSink::Fields(Rc::new(Cell::new(Some(FieldsSink {
|
|
|
|
finish: item(seq![rtmp.clone(), ".finish().wrap()"]),
|
|
|
|
vec_expr: item(seq![rtmp.clone(), ".fields_vec_mut()"]),
|
2023-01-28 21:38:14 +00:00
|
|
|
body,
|
2021-06-29 14:54:29 +00:00
|
|
|
})))),
|
|
|
|
is_struct: vc.is_struct,
|
2023-07-21 16:15:30 +00:00
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
|
|
|
CompoundPattern::Tuple { patterns } => {
|
|
|
|
let mut fields_sink = sequenceify(ctxt, vc);
|
|
|
|
fixed_sequence_parser(ctxt, patterns, &mut fields_sink, vc.is_struct);
|
|
|
|
finish(fields_sink)
|
|
|
|
}
|
|
|
|
CompoundPattern::TuplePrefix { fixed, variable } => {
|
|
|
|
let mut fields_sink = sequenceify(ctxt, vc);
|
|
|
|
fixed_sequence_parser(ctxt, fixed, &mut fields_sink, vc.is_struct);
|
|
|
|
named_pattern_unparser(
|
|
|
|
ctxt,
|
|
|
|
&promote(variable),
|
|
|
|
&ValueContext {
|
2021-06-29 14:54:29 +00:00
|
|
|
src: vc.src.clone(),
|
|
|
|
sink: ValueSink::Fields(Rc::new(Cell::new(Some(fields_sink)))),
|
|
|
|
is_struct: true,
|
2023-07-21 16:15:30 +00:00
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
|
|
|
CompoundPattern::Dict { entries } => {
|
|
|
|
let dtmp = ctxt.gentempname();
|
|
|
|
let mut body = Vec::new();
|
|
|
|
ctxt.declare_compound(&mut body, &dtmp, item("preserves::value::Map::new()"));
|
|
|
|
for (key_lit, value_pat) in entries.0.iter() {
|
|
|
|
body.push(item(seq![
|
|
|
|
dtmp.clone(),
|
|
|
|
".insert",
|
|
|
|
parens![
|
2021-06-29 14:54:29 +00:00
|
|
|
seq![parens![ctxt.m.define_literal(key_lit)], ".clone()"],
|
2023-07-21 16:15:30 +00:00
|
|
|
named_pattern_unparser(
|
|
|
|
ctxt,
|
|
|
|
&promote(value_pat),
|
|
|
|
&normal_none(vc.is_struct)
|
|
|
|
)
|
|
|
|
],
|
|
|
|
";"
|
|
|
|
]));
|
2021-06-29 14:54:29 +00:00
|
|
|
}
|
2023-07-21 16:15:30 +00:00
|
|
|
body.push(item(seq![
|
|
|
|
"preserves::value::Value::Dictionary(",
|
|
|
|
dtmp,
|
|
|
|
").wrap()"
|
|
|
|
]));
|
|
|
|
item(codeblock(body))
|
2021-06-29 14:54:29 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-21 16:15:30 +00:00
|
|
|
fn sequenceify<'a>(ctxt: &mut FunctionContext, vc: &'a ValueContext) -> FieldsSink {
|
2021-06-29 14:54:29 +00:00
|
|
|
match vc {
|
2023-07-21 16:15:30 +00:00
|
|
|
ValueContext {
|
|
|
|
sink: ValueSink::Fields(fields_sink),
|
|
|
|
..
|
|
|
|
} => (**fields_sink).take().unwrap(),
|
2021-06-29 14:54:29 +00:00
|
|
|
_ => {
|
2021-07-21 19:52:20 +00:00
|
|
|
let rtmp = ctxt.gentempname();
|
2021-06-29 14:54:29 +00:00
|
|
|
let mut body = Vec::new();
|
2021-07-21 19:52:20 +00:00
|
|
|
ctxt.declare_compound(&mut body, &rtmp, item("std::vec::Vec::new()"));
|
2021-06-29 14:54:29 +00:00
|
|
|
FieldsSink {
|
|
|
|
finish: item(seq![
|
2023-07-21 16:15:30 +00:00
|
|
|
"preserves::value::Value::Sequence",
|
|
|
|
parens![rtmp.clone()],
|
|
|
|
".wrap()"
|
|
|
|
]),
|
2021-07-21 19:52:20 +00:00
|
|
|
vec_expr: item(rtmp),
|
2023-01-28 21:38:14 +00:00
|
|
|
body,
|
2021-06-29 14:54:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn finish(mut fields_sink: FieldsSink) -> Item {
|
|
|
|
fields_sink.body.push(fields_sink.finish);
|
2021-09-16 14:31:59 +00:00
|
|
|
item(codeblock(fields_sink.body))
|
2021-06-29 14:54:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn fixed_sequence_parser(
|
|
|
|
ctxt: &mut FunctionContext,
|
|
|
|
patterns: &Vec<NamedPattern>,
|
|
|
|
fields_sink: &mut FieldsSink,
|
|
|
|
is_struct: bool,
|
|
|
|
) {
|
|
|
|
for p in patterns {
|
2023-07-21 16:15:30 +00:00
|
|
|
fields_sink.body.push(item(seq![
|
|
|
|
fields_sink.vec_expr.clone(),
|
|
|
|
".push",
|
|
|
|
parens![named_pattern_unparser(ctxt, p, &normal_none(is_struct))],
|
|
|
|
";"
|
|
|
|
]));
|
2021-06-29 14:54:29 +00:00
|
|
|
}
|
|
|
|
}
|