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

468 lines
15 KiB
Rust
Raw Normal View History

2021-06-29 20:32:35 +00:00
use crate::gen::schema::*;
2021-06-28 14:35:45 +00:00
use crate::syntax::block::constructors::*;
2023-07-21 16:15:30 +00:00
use crate::syntax::block::Item;
use crate::*;
2021-06-29 14:54:29 +00:00
use super::context::FunctionContext;
use super::context::ModuleContext;
use super::context::ModuleContextMode;
use super::context::RefRenderStyle;
2021-06-28 14:35:45 +00:00
use super::names;
use super::types::*;
2021-08-12 19:28:24 +00:00
#[derive(Debug)]
pub struct ParserPlugin;
impl compiler::Plugin for ParserPlugin {
2023-07-21 16:15:30 +00:00
fn generate_definition(
&self,
module_ctxt: &mut ModuleContext,
definition_name: &str,
definition: &Definition,
) {
if let ModuleContextMode::TargetGeneric = module_ctxt.mode {
gen_definition_parser(module_ctxt, definition_name, definition)
}
}
}
2021-06-28 20:25:41 +00:00
pub fn gen_definition_parser(m: &mut ModuleContext, n: &str, d: &Definition) {
let ty = definition_type(&m.module_path, Purpose::Codegen, n, d);
2023-07-21 16:15:30 +00:00
m.define_function(n, |mut ctxt| {
let mut body = vec![];
2021-06-28 14:35:45 +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);
for NamedAlternative {
variant_label: name,
pattern: pat,
} in ps
{
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(&(n.to_owned() + "::" + name), |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, &pattern_type(pat), dest, &mut body);
2023-07-21 16:15:30 +00:00
item(seq![
"fn ",
fname.clone(),
ctxt.m.parse_unparse_generic_decls(&ty),
"(_ctxt: _L, value: &",
ctxt.m.any_type(),
") -> ",
"std::result::Result<",
names::render_constructor(n),
ty.generic_arg(ctxt.m),
", _support::ParseError> ",
codeblock(body)
])
});
body.push(item(seq![
"if let Ok(r) = ",
fname,
"(_ctxt, value) { return Ok(r); }"
]));
2021-06-28 20:25:41 +00:00
}
2023-07-21 16:15:30 +00:00
body.push(item(seq![ctxt.err_code()]));
}
Definition::And {
pattern_0,
pattern_1,
pattern_n,
} => {
let mut ps = vec![&**pattern_0, &**pattern_1];
ps.extend(pattern_n);
for e in &ps {
named_pattern_parser(&mut ctxt, e, "value", None, &mut body);
2021-06-28 14:35:45 +00:00
}
2023-07-21 16:15:30 +00:00
construct(
&ctxt,
item(names::render_constructor(n)),
true,
&record_type(&ps),
None,
&mut body,
);
2021-06-28 14:35:45 +00:00
}
2023-07-21 16:15:30 +00:00
Definition::Pattern(p) => {
let dest = pattern_parser(&mut ctxt, p, "value", None, &mut body);
let dest = dest.as_ref().map(String::as_str);
construct(
&ctxt,
item(names::render_constructor(n)),
true,
&pattern_type(p),
dest,
&mut body,
);
}
}
2021-06-28 14:35:45 +00:00
2023-07-21 16:15:30 +00:00
item(seq![
"impl",
ctxt.m.parse_unparse_generic_decls(&ty),
" _support::Parse",
anglebrackets!["_L", ctxt.m.any_type()],
" for ",
names::render_constructor(n),
ty.generic_arg(ctxt.m),
" ",
codeblock![seq![
"fn parse(_ctxt: _L, value: &",
ctxt.m.any_type(),
")",
" -> std::result::Result<Self, _support::ParseError> ",
codeblock(body)
]]
])
});
2021-06-28 14:35:45 +00:00
}
fn construct(
ctxt: &FunctionContext,
ctorname: Item,
2021-06-28 15:26:41 +00:00
is_struct: bool,
2021-06-29 14:54:29 +00:00
ty: &TSimple,
2021-06-28 14:35:45 +00:00
dest: Option<&str>,
body: &mut Vec<Item>,
) {
match ty {
2023-07-21 16:15:30 +00:00
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()
),
")"
])),
2021-06-28 14:35:45 +00:00
}
}
2021-06-28 15:26:41 +00:00
fn store_wrap(is_struct: bool, ty: &TField, expr: &str) -> String {
2021-06-28 14:35:45 +00:00
match ty {
2023-07-21 16:15:30 +00:00
TField::Unit | TField::Array(_) | TField::Set(_) | TField::Map(_, _) => expr.to_owned(),
TField::Ref(_) => {
2021-06-28 15:26:41 +00:00
if is_struct {
expr.to_owned()
} else {
format!("std::boxed::Box::new({})", expr)
2023-07-21 16:15:30 +00:00
}
}
TField::Base(_) | TField::Any | TField::Embedded => format!("{}.clone()", expr),
2021-06-28 14:35:45 +00:00
}
}
fn simple_pattern_parser(
ctxt: &mut FunctionContext,
2021-06-28 20:25:41 +00:00
p: &SimplePattern,
2021-06-28 14:35:45 +00:00
src: &str,
sequence_base: Option<usize>,
body: &mut Vec<Item>,
2021-06-28 20:25:41 +00:00
) -> String {
2021-06-28 14:35:45 +00:00
let dest = ctxt.gentempname();
2021-06-28 20:25:41 +00:00
match p {
SimplePattern::Any => {
ctxt.define_atom(body, &dest, item(src.to_owned()));
2021-06-28 20:25:41 +00:00
dest
2023-07-21 16:15:30 +00:00
}
2021-06-28 20:25:41 +00:00
SimplePattern::Atom { atom_kind: k } => {
2021-06-28 20:38:30 +00:00
let converter = match &**k {
AtomKind::Boolean => "to_boolean",
AtomKind::Double => "to_double",
AtomKind::SignedInteger => "to_signedinteger",
AtomKind::String => "to_string",
AtomKind::ByteString => "to_bytestring",
AtomKind::Symbol => "to_symbol",
};
2023-07-21 16:15:30 +00:00
ctxt.define_atom(
body,
&dest,
item(seq![src.to_owned(), ".value().", converter, "()?"]),
);
2021-06-28 20:25:41 +00:00
dest
2023-07-21 16:15:30 +00:00
}
2021-06-28 20:25:41 +00:00
SimplePattern::Embedded { .. } => {
2023-07-21 16:15:30 +00:00
ctxt.define_atom(
body,
&dest,
item(seq![parens![seq![
src.to_owned(),
".value().to_embedded()?"
]]]),
);
2021-06-28 20:25:41 +00:00
dest
2023-07-21 16:15:30 +00:00
}
2021-06-28 20:25:41 +00:00
SimplePattern::Lit { value } => {
2023-07-21 16:15:30 +00:00
body.push(item(seq![
"if ",
src.to_owned(),
" != ",
ctxt.m.define_literal(value),
" { return ",
ctxt.err_code(),
"; }"
]));
ctxt.define_atom(body, &dest, item("()"));
2021-06-28 20:25:41 +00:00
dest
2023-07-21 16:15:30 +00:00
}
2021-06-28 20:25:41 +00:00
SimplePattern::Seqof { pattern } => {
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, pattern, &tmp, None, &mut inner);
2023-07-21 16:15:30 +00:00
inner.push(item(seq![
dest.to_owned(),
".push(",
store_wrap(true, &field_type(pattern), &item_dest),
");"
]));
ctxt.declare_compound(body, &dest, item("std::vec::Vec::new()"));
2023-07-21 16:15:30 +00:00
body.push(item(seq![
"for ",
tmp.to_owned(),
" in &",
src.to_owned(),
brackets![seq![n.to_string(), ".."]],
" ",
codeblock(inner)
]));
2021-06-28 20:25:41 +00:00
dest
2023-07-21 16:15:30 +00:00
}
2021-06-28 20:25:41 +00:00
SimplePattern::Setof { pattern } => {
let tmp = ctxt.gentempname();
let mut inner = Vec::new();
let item_dest = simple_pattern_parser(ctxt, pattern, &tmp, None, &mut inner);
2023-07-21 16:15:30 +00:00
inner.push(item(seq![
dest.to_owned(),
".insert(",
store_wrap(true, &field_type(pattern), &item_dest),
");"
]));
ctxt.declare_compound(body, &dest, item("preserves::value::Set::new()"));
2023-07-21 16:15:30 +00:00
body.push(item(seq![
"for ",
tmp.to_owned(),
" in ",
src.to_owned(),
".value().to_set()?",
" ",
codeblock(inner)
]));
2021-06-28 20:25:41 +00:00
dest
2023-07-21 16:15:30 +00:00
}
2021-06-28 20:25:41 +00:00
SimplePattern::Dictof { key, value } => {
let tmp_key = ctxt.gentempname();
let tmp_value = ctxt.gentempname();
let mut inner = Vec::new();
let key_dest = simple_pattern_parser(ctxt, key, &tmp_key, None, &mut inner);
let value_dest = simple_pattern_parser(ctxt, value, &tmp_value, None, &mut inner);
inner.push(item(seq![
2023-07-21 16:15:30 +00:00
dest.to_owned(),
".insert(",
store_wrap(true, &field_type(key), &key_dest),
", ",
store_wrap(true, &field_type(value), &value_dest),
");"
]));
ctxt.declare_compound(body, &dest, item("preserves::value::Map::new()"));
2023-07-21 16:15:30 +00:00
body.push(item(seq![
"for (",
tmp_key.to_owned(),
", ",
tmp_value.to_owned(),
")",
" in ",
src.to_owned(),
".value().to_dictionary()?",
" ",
codeblock(inner)
]));
2021-06-28 20:25:41 +00:00
dest
2023-07-21 16:15:30 +00:00
}
2021-06-28 20:25:41 +00:00
SimplePattern::Ref(r) => {
let tf = name![ctxt.m.render_ref(&**r, RefRenderStyle::Bare), "parse"];
2023-07-21 16:15:30 +00:00
ctxt.define_atom(
body,
&dest,
item(seq![tf, parens!["_ctxt", src.to_owned()], "?"]),
);
2021-06-28 20:25:41 +00:00
dest
2023-07-21 16:15:30 +00:00
}
2021-06-28 14:35:45 +00:00
}
}
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();
2023-07-21 16:15:30 +00:00
ctxt.define_atom(
body,
&tmp,
item(seq![src.to_owned(), ".value().to_sequence()?"]),
);
2021-06-28 14:35:45 +00:00
(tmp, 0)
}
}
}
fn fixed_sequence_parser(
ctxt: &mut FunctionContext,
base: usize,
2021-06-28 20:25:41 +00:00
ps: &[NamedPattern],
2021-06-28 14:35:45 +00:00
src: &str,
body: &mut Vec<Item>,
) {
let mut i = base;
let required_count = ps.len();
if required_count > 0 {
2023-07-21 16:15:30 +00:00
body.push(item(seq![
"if ",
src.to_owned(),
".len()",
if base > 0 {
seq![" - ", base.to_string()]
} else {
seq![]
},
" < ",
required_count.to_string(),
" { return ",
ctxt.err_code(),
"; }"
]));
}
2021-06-28 14:35:45 +00:00
for p in ps {
2021-06-28 20:25:41 +00:00
named_pattern_parser(ctxt, p, &format!("(&{}[{}])", src, i), None, body);
2021-06-28 14:35:45 +00:00
i += 1;
}
}
2021-06-28 20:25:41 +00:00
fn named_pattern_parser(
ctxt: &mut FunctionContext,
p: &NamedPattern,
src: &str,
sequence_base: Option<usize>,
body: &mut Vec<Item>,
) {
match p {
NamedPattern::Anonymous(p) => {
pattern_parser(ctxt, p, src, sequence_base, body);
2023-07-21 16:15:30 +00:00
}
2021-06-28 20:25:41 +00:00
NamedPattern::Named(b) => {
2023-07-21 16:15:30 +00:00
let Binding { name, pattern } = &**b;
2021-06-28 20:25:41 +00:00
let dest = simple_pattern_parser(ctxt, pattern, src, sequence_base, body);
let capture_ty = field_type(pattern);
ctxt.capture(names::render_fieldname(name), capture_ty, dest);
}
}
}
2021-06-28 14:35:45 +00:00
fn pattern_parser(
ctxt: &mut FunctionContext,
2021-06-28 20:25:41 +00:00
p: &Pattern,
2021-06-28 14:35:45 +00:00
src: &str,
sequence_base: Option<usize>,
body: &mut Vec<Item>,
) -> Option<String> {
2021-06-28 20:25:41 +00:00
match p {
2023-07-21 16:15:30 +00:00
Pattern::SimplePattern(s) => Some(simple_pattern_parser(ctxt, s, src, sequence_base, body)),
2021-06-28 20:25:41 +00:00
Pattern::CompoundPattern(c) => {
match &**c {
CompoundPattern::Rec { label, fields } => {
2021-06-28 14:35:45 +00:00
let rtmp = ctxt.gentempname();
2023-07-21 16:15:30 +00:00
ctxt.define_atom(
body,
&rtmp,
item(seq![src.to_owned(), ".value().to_record(None)?"]),
);
2021-06-28 20:25:41 +00:00
named_pattern_parser(ctxt, &**label, &format!("{}.label()", rtmp), None, body);
2023-07-21 16:15:30 +00:00
named_pattern_parser(
ctxt,
&**fields,
&format!("{}.fields()", rtmp),
Some(0),
body,
);
}
2021-06-28 20:25:41 +00:00
CompoundPattern::Tuple { patterns } => {
2021-06-28 14:35:45 +00:00
let (src, n) = sequenceify(ctxt, src, sequence_base, body);
2021-06-28 20:25:41 +00:00
fixed_sequence_parser(ctxt, n, patterns, &src, body);
2023-07-21 16:15:30 +00:00
}
2021-06-28 20:25:41 +00:00
CompoundPattern::TuplePrefix { fixed, variable } => {
2021-06-28 14:35:45 +00:00
let (src, n) = sequenceify(ctxt, src, sequence_base, body);
fixed_sequence_parser(ctxt, n, fixed, &src, body);
2023-07-21 16:15:30 +00:00
named_pattern_parser(
ctxt,
&promote(variable),
&src,
Some(n + fixed.len()),
body,
);
}
2021-06-28 20:25:41 +00:00
CompoundPattern::Dict { entries } => {
2021-06-28 14:35:45 +00:00
let dtmp = ctxt.gentempname();
2023-07-21 16:15:30 +00:00
ctxt.define_atom(
body,
&dtmp,
item(seq![src.to_owned(), ".value().to_dictionary()?"]),
);
2021-06-28 20:25:41 +00:00
for (key_lit, value_pat) in entries.0.iter() {
2021-06-28 14:35:45 +00:00
let vtmp = ctxt.gentempname();
let init_expr = item(seq![
2023-07-21 16:15:30 +00:00
dtmp.to_owned(),
".get",
parens![ctxt.m.define_literal(key_lit)],
".ok_or_else(|| ",
ctxt.conformance_err_code(),
")?"
]);
ctxt.define_atom(body, &vtmp, init_expr);
2021-06-28 20:25:41 +00:00
named_pattern_parser(ctxt, &promote(value_pat), &vtmp, None, body);
2021-06-28 14:35:45 +00:00
}
}
}
2021-06-28 20:25:41 +00:00
None
2023-07-21 16:15:30 +00:00
}
2021-06-28 14:35:45 +00:00
}
}