Fix multi-schema bundles after refactor

This commit is contained in:
Tony Garnock-Jones 2021-09-15 14:03:33 +02:00
parent 985a0b6795
commit e56b62cfbb
9 changed files with 383 additions and 324 deletions

View File

@ -58,6 +58,11 @@ pub enum CaptureMode {
Indefinite(Vec<Item>), Indefinite(Vec<Item>),
} }
pub enum RefRenderStyle {
Bare,
Qualified,
}
lazy_static! { lazy_static! {
static ref ID_RE: regex::Regex = regex::Regex::new(r"^[a-zA-Z][a-zA-Z_0-9]*$").unwrap(); static ref ID_RE: regex::Regex = regex::Regex::new(r"^[a-zA-Z][a-zA-Z_0-9]*$").unwrap();
} }
@ -74,7 +79,14 @@ impl<'b> BundleContext<'b> {
} }
pub fn type_for_name(&self, r: &Ref) -> Option<&types::TDefinition> { pub fn type_for_name(&self, r: &Ref) -> Option<&types::TDefinition> {
self.types.get(r) if r.module.0.is_empty() {
panic!("BundleContext::type_for_name with module-relative ref {:?}", r);
}
let result = self.types.get(r);
if result.is_none() && !self.config.module_aliases.contains_key(&r.module.0) {
panic!("Attempted to lookup unknown type {:?}", r)
}
result
} }
pub fn define_literal(&mut self, v: &IOValue) -> String { pub fn define_literal(&mut self, v: &IOValue) -> String {
@ -138,7 +150,7 @@ impl<'m, 'b> ModuleContext<'m, 'b> {
self.functiondefs.push(i) self.functiondefs.push(i)
} }
pub fn render_ref(&self, r: &Ref, with_generic_args: bool) -> Item { pub fn render_ref(&self, r: &Ref, style: RefRenderStyle) -> Item {
let base = match self.bundle.config.module_aliases.get(&r.module.0) { let base = match self.bundle.config.module_aliases.get(&r.module.0) {
None => None =>
if r.module.0.is_empty() { if r.module.0.is_empty() {
@ -153,43 +165,32 @@ impl<'m, 'b> ModuleContext<'m, 'b> {
Some(s) => Some(s) =>
item(name![s.to_owned(), r.name.to_owned()]) item(name![s.to_owned(), r.name.to_owned()])
}; };
if with_generic_args && self.ref_has_embedded(r) { let q = self.ref_has_embedded(r);
item(seq![base, anglebrackets!["_Any"]]) match style {
} else { RefRenderStyle::Bare =>
base base,
RefRenderStyle::Qualified =>
if q { item(seq![base, anglebrackets!["_Value"]]) } else { base },
} }
} }
pub fn any_type(&self) -> &'static str { pub fn any_type(&self) -> &'static str {
"_Any" "_Value"
}
pub fn qualify(&self, r: &Ref) -> Ref {
if r.module.0.is_empty() {
Ref { module: self.module_path.clone(), name: r.name.clone() }
} else {
r.clone()
}
}
pub fn type_for_name(&self, r: &Ref) -> Option<&types::TDefinition> {
self.bundle.type_for_name(&self.qualify(r))
} }
pub fn ref_has_embedded(&self, r: &Ref) -> bool { pub fn ref_has_embedded(&self, r: &Ref) -> bool {
match self.type_for_name(r) { let r = r.qualify(&self.module_path);
Some(ty) => ty.has_embedded(self), self.bundle.type_for_name(&r).map(|ty| ty.has_embedded(self.bundle)).unwrap_or(false)
None => false, // TODO: should this be configurable? // ^ TODO: should the "false" be configurable?
}
} }
pub fn literals_generic_decls(&self) -> Item { pub fn literals_generic_decls(&self) -> Item {
item(anglebrackets!["_Any: preserves::value::NestedValue"]) item(anglebrackets!["_Value: preserves::value::NestedValue"])
} }
pub fn literals_generic_decls_with_defaults(&self) -> Item { pub fn literals_generic_decls_with_defaults(&self) -> Item {
item(anglebrackets![ item(anglebrackets![
seq!["_Any: preserves::value::NestedValue = ", seq!["_Value: preserves::value::NestedValue = ",
if self.schema.embedded_type == EmbeddedTypeName::False { if self.schema.embedded_type == EmbeddedTypeName::False {
"preserves::value::IOValue" "preserves::value::IOValue"
} else { } else {
@ -198,11 +199,11 @@ impl<'m, 'b> ModuleContext<'m, 'b> {
} }
pub fn literals_generic_arg(&self) -> Item { pub fn literals_generic_arg(&self) -> Item {
item("<_Any>") item("<_Value>")
} }
pub fn literals_type(&self) -> Item { pub fn literals_type(&self) -> Item {
item(seq!["&", self.literals_base_type(), self.literals_generic_arg()]) item(seq![self.literals_base_type(), self.literals_generic_arg()])
} }
pub fn literals_base_type(&self) -> Item { pub fn literals_base_type(&self) -> Item {

View File

@ -6,8 +6,10 @@ pub mod types;
pub mod unparsers; pub mod unparsers;
use crate::*; use crate::*;
use crate::support::Parse;
use crate::compiler::context::*; use crate::compiler::context::*;
use crate::gen::Literals; use crate::gen::Literals;
use crate::gen::schema;
use crate::gen::schema::*; use crate::gen::schema::*;
use crate::syntax::block::{Formatter, Item}; use crate::syntax::block::{Formatter, Item};
use crate::syntax::block::constructors::*; use crate::syntax::block::constructors::*;
@ -101,11 +103,13 @@ impl CompilerConfig {
} }
fn build_type_cache(&self) -> Map<Ref, types::TDefinition> { fn build_type_cache(&self) -> Map<Ref, types::TDefinition> {
self.bundle.iter().flat_map( self.bundle.iter().flat_map(|(modpath, s)| {
|(modpath, s)| s.definitions.0.iter().map( let modpath = ModulePath(modpath.clone());
move |(name, def)| (Ref { module: ModulePath(modpath.clone()), name: name.clone() }, s.definitions.0.iter().map(move |(name, def)| {
types::definition_type(def)))) let ty = types::definition_type(&modpath, name, def);
.collect() (ty.self_ref.clone(), ty)
})
}).collect()
} }
fn generate_definition( fn generate_definition(
@ -150,6 +154,16 @@ fn write_if_changed(output_path: &PathBuf, contents: &[u8]) -> io::Result<()> {
f.write_all(contents) f.write_all(contents)
} }
impl Ref {
pub fn qualify(&self, default_module_path: &schema::ModulePath) -> Ref {
if self.module.0.is_empty() {
Ref { module: default_module_path.clone(), name: self.name.clone() }
} else {
self.clone()
}
}
}
impl Schema { impl Schema {
pub fn has_embedded_type(&self) -> bool { pub fn has_embedded_type(&self) -> bool {
self.embedded_type != EmbeddedTypeName::False self.embedded_type != EmbeddedTypeName::False
@ -194,6 +208,8 @@ pub fn compile(config: &CompilerConfig) -> io::Result<()> {
"use std::convert::TryFrom;", "use std::convert::TryFrom;",
format!("use {}::support as _support;", &config.support_crate), format!("use {}::support as _support;", &config.support_crate),
"use _support::Deserialize;", "use _support::Deserialize;",
"use _support::Parse;",
"use _support::Unparse;",
"use _support::preserves;", "use _support::preserves;",
"use preserves::value::Domain;", "use preserves::value::Domain;",
"use preserves::value::NestedValue;", "use preserves::value::NestedValue;",

View File

@ -3,7 +3,10 @@ use crate::gen::schema::*;
use crate::syntax::block::Item; use crate::syntax::block::Item;
use crate::syntax::block::constructors::*; use crate::syntax::block::constructors::*;
use super::context::{ModuleContextMode, ModuleContext, FunctionContext}; use super::context::FunctionContext;
use super::context::ModuleContext;
use super::context::ModuleContextMode;
use super::context::RefRenderStyle;
use super::names; use super::names;
use super::types::*; use super::types::*;
@ -19,7 +22,7 @@ impl compiler::Plugin for ParserPlugin {
} }
pub fn gen_definition_parser(m: &mut ModuleContext, n: &str, d: &Definition) { pub fn gen_definition_parser(m: &mut ModuleContext, n: &str, d: &Definition) {
let ty = definition_type(d); let ty = definition_type(&m.module_path, n, d);
m.define_function( m.define_function(
n, n,
@ -41,7 +44,7 @@ pub fn gen_definition_parser(m: &mut ModuleContext, n: &str, d: &Definition) {
let dest = dest.as_ref().map(String::as_str); let dest = dest.as_ref().map(String::as_str);
construct(&ctxt, ctorname, false, &pattern_type(pat), dest, &mut body); construct(&ctxt, ctorname, false, &pattern_type(pat), dest, &mut body);
item(seq!["fn ", fname.clone(), ctxt.m.literals_generic_decls(), item(seq!["fn ", fname.clone(), ctxt.m.literals_generic_decls(),
"(_ctxt: ", ctxt.m.literals_type(), ", value: &", ctxt.m.any_type(), ") -> ", "(_ctxt: &", ctxt.m.literals_type(), ", value: &", ctxt.m.any_type(), ") -> ",
"std::result::Result<", "std::result::Result<",
names::render_constructor(n), ty.generic_arg(ctxt.m), names::render_constructor(n), ty.generic_arg(ctxt.m),
", _support::ParseError> ", ", _support::ParseError> ",
@ -66,36 +69,16 @@ pub fn gen_definition_parser(m: &mut ModuleContext, n: &str, d: &Definition) {
} }
} }
let (topdecl, innerdecl) = if ty.has_embedded(ctxt.m) { item(seq!["impl", ctxt.m.literals_generic_decls(),
(ctxt.m.literals_generic_decls(), item("")) " _support::Parse", anglebrackets![ctxt.m.literals_type(),
} else { ctxt.m.any_type()], " for ",
(item(""), ctxt.m.literals_generic_decls())
};
item(seq!["impl", topdecl, " ",
names::render_constructor(n), ty.generic_arg(ctxt.m), " ", names::render_constructor(n), ty.generic_arg(ctxt.m), " ",
block![ block![
seq!["pub fn parse", innerdecl, "(_ctxt: ", ctxt.m.literals_type(), seq!["fn parse(_ctxt: &", ctxt.m.literals_type(),
", value: &", ctxt.m.any_type(), ") -> ", ", value: &", ctxt.m.any_type(), ") -> ",
"std::result::Result<Self, _support::ParseError> ", "std::result::Result<Self, _support::ParseError> ",
codeblock(body)]]]) codeblock(body)]]])
}); });
// m.define_function(
// n,
// |ctxt| {
// item(seq!["impl", ctxt.m.literals_generic_decls(),
// " std::convert::TryFrom", anglebrackets![seq!["&", ctxt.m.any_type()]], " for ",
// names::render_constructor(n), ty.generic_arg(ctxt.m), " ",
// block![
// seq!["type Error = _support::ParseError;"],
// seq!["fn try_from(value: &", ctxt.m.any_type(), ") -> ",
// "std::result::Result<Self, _support::ParseError> ",
// codeblock![
// seq!["Self::parse(",
// ctxt.m.literals_base_type(), "::default()",
// ", value)"]]]]])
// });
} }
fn construct( fn construct(
@ -214,7 +197,7 @@ fn simple_pattern_parser(
dest dest
}, },
SimplePattern::Ref(r) => { SimplePattern::Ref(r) => {
let tf = name![ctxt.m.render_ref(&**r, false), "parse"]; let tf = name![ctxt.m.render_ref(&**r, RefRenderStyle::Bare), "parse"];
ctxt.define_atom(body, ctxt.define_atom(body,
&dest, &dest,
item(seq![tf, parens!["_ctxt", src.to_owned()], "?"])); item(seq![tf, parens!["_ctxt", src.to_owned()], "?"]));

View File

@ -11,7 +11,10 @@ use preserves::value::IOValue;
use preserves::value::NestedValue; use preserves::value::NestedValue;
use preserves::value::ValueClass; use preserves::value::ValueClass;
use super::context::{ModuleContextMode, ModuleContext, FunctionContext}; use super::context::FunctionContext;
use super::context::ModuleContext;
use super::context::ModuleContextMode;
use super::context::RefRenderStyle;
use super::names; use super::names;
use super::types::*; use super::types::*;
@ -75,7 +78,7 @@ impl BoundaryTracker {
} }
pub fn gen_definition_reader(m: &mut ModuleContext, n: &str, d: &Definition) { pub fn gen_definition_reader(m: &mut ModuleContext, n: &str, d: &Definition) {
let ty = definition_type(d); let ty = definition_type(&m.module_path, n, d);
m.define_function( m.define_function(
n, n,
@ -100,8 +103,8 @@ pub fn gen_definition_reader(m: &mut ModuleContext, n: &str, d: &Definition) {
item(seq![ item(seq![
"fn ", fname.clone(), anglebrackets![ "fn ", fname.clone(), anglebrackets![
"'de", "'de",
"_Any: preserves::value::NestedValue", "_Value: preserves::value::NestedValue",
"R: _support::Reader<'de, _Any>"], "R: _support::Reader<'de, _Value>"],
"(r: &mut R) -> ", "(r: &mut R) -> ",
"std::result::Result<", "std::result::Result<",
names::render_constructor(n), ty.generic_arg(ctxt.m), names::render_constructor(n), ty.generic_arg(ctxt.m),
@ -139,9 +142,9 @@ pub fn gen_definition_reader(m: &mut ModuleContext, n: &str, d: &Definition) {
item(seq![ item(seq![
"impl", anglebrackets!["'de", "impl", anglebrackets!["'de",
"_Any: preserves::value::NestedValue", "_Value: preserves::value::NestedValue",
"R: _support::Reader<'de, _Any>"], " ", "R: _support::Reader<'de, _Value>"], " ",
"_support::Deserialize", anglebrackets!["'de", "_Any", "R"], " ", "_support::Deserialize", anglebrackets!["'de", "_Value", "R"], " ",
"for ", names::render_constructor(n), ty.generic_arg(ctxt.m), " ", block![ "for ", names::render_constructor(n), ty.generic_arg(ctxt.m), " ", block![
seq!["fn deserialize(r: &mut R) -> ", seq!["fn deserialize(r: &mut R) -> ",
"std::result::Result<Self, _support::ParseError> ", "std::result::Result<Self, _support::ParseError> ",
@ -426,7 +429,7 @@ fn simple_pattern_reader(
dest dest
}, },
SimplePattern::Ref(r) => { SimplePattern::Ref(r) => {
let tf = name![ctxt.m.render_ref(&**r, false), "deserialize"]; let tf = name![ctxt.m.render_ref(&**r, RefRenderStyle::Bare), "deserialize"];
ctxt.define_atom(body, &dest, item(seq![tf, "(r)?"])); ctxt.define_atom(body, &dest, item(seq![tf, "(r)?"]));
dest dest
}, },

View File

@ -5,11 +5,20 @@ use crate::gen::schema::*;
use preserves::value::Set; use preserves::value::Set;
use super::context::{ModuleContextMode, ModuleContext}; use super::context::BundleContext;
use super::context::ModuleContext;
use super::context::ModuleContextMode;
use super::context::RefRenderStyle;
use super::names; use super::names;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum TDefinition { pub struct TDefinition {
pub self_ref: Ref,
pub body: TDefinitionBody,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum TDefinitionBody {
Union(Vec<(String, TSimple)>), Union(Vec<(String, TSimple)>),
Simple(TSimple), Simple(TSimple),
} }
@ -42,7 +51,7 @@ impl compiler::Plugin for TypePlugin {
fn generate_module(&self, m: &mut ModuleContext) { fn generate_module(&self, m: &mut ModuleContext) {
if let EmbeddedTypeName::Ref(r) = &m.schema.embedded_type { if let EmbeddedTypeName::Ref(r) = &m.schema.embedded_type {
m.define_type(item(vertical(false, seq![ m.define_type(item(vertical(false, seq![
seq!["pub type _Dom = ", m.render_ref(&*r, true), ";"], seq!["pub type _Dom = ", m.render_ref(&*r, RefRenderStyle::Bare), ";"],
seq!["pub type _Ptr = std::sync::Arc<_Dom>;"], seq!["pub type _Ptr = std::sync::Arc<_Dom>;"],
seq!["pub type _Any = preserves::value::ArcValue<_Ptr>;"] seq!["pub type _Any = preserves::value::ArcValue<_Ptr>;"]
]))); ])));
@ -51,7 +60,7 @@ impl compiler::Plugin for TypePlugin {
fn generate_definition(&self, m: &mut ModuleContext, n: &str, d: &Definition) { fn generate_definition(&self, m: &mut ModuleContext, n: &str, d: &Definition) {
if let ModuleContextMode::TargetGeneric = m.mode { if let ModuleContextMode::TargetGeneric = m.mode {
let ty = definition_type(d); let ty = definition_type(&m.module_path, n, d);
m.define_type(item(ty.render(m, n))); m.define_type(item(ty.render(m, n)));
m.define_type(item(seq![ m.define_type(item(seq![
"impl", ty.generic_decl(m), " preserves::value::Domain for ", "impl", ty.generic_decl(m), " preserves::value::Domain for ",
@ -60,14 +69,17 @@ impl compiler::Plugin for TypePlugin {
} }
} }
pub fn definition_type(d: &Definition) -> TDefinition { pub fn definition_type(module: &ModulePath, n: &str, d: &Definition) -> TDefinition {
match d { TDefinition {
self_ref: Ref { module: module.clone(), name: n.to_owned() },
body: match d {
Definition::Or { pattern_0, pattern_1, pattern_n } => Definition::Or { pattern_0, pattern_1, pattern_n } =>
TDefinition::Union(or_definition_type(pattern_0, pattern_1, pattern_n)), TDefinitionBody::Union(or_definition_type(pattern_0, pattern_1, pattern_n)),
Definition::And { pattern_0, pattern_1, pattern_n } => Definition::And { pattern_0, pattern_1, pattern_n } =>
TDefinition::Simple(and_definition_type(pattern_0, pattern_1, pattern_n)), TDefinitionBody::Simple(and_definition_type(pattern_0, pattern_1, pattern_n)),
Definition::Pattern(p) => Definition::Pattern(p) =>
TDefinition::Simple(pattern_type(p)), TDefinitionBody::Simple(pattern_type(p)),
}
} }
} }
@ -183,8 +195,8 @@ impl TField {
fn render(&self, ctxt: &ModuleContext, box_needed: bool) -> impl Emittable { fn render(&self, ctxt: &ModuleContext, box_needed: bool) -> impl Emittable {
match self { match self {
TField::Unit => seq!["()"], TField::Unit => seq!["()"],
TField::Any => seq!["_Any"], TField::Any => seq!["_Value"],
TField::Embedded => seq!["_Ptr"], TField::Embedded => seq!["_Value::D"],
TField::Array(t) => seq!["std::vec::Vec<", t.render(ctxt, false), ">"], TField::Array(t) => seq!["std::vec::Vec<", t.render(ctxt, false), ">"],
TField::Set(t) => seq!["preserves::value::Set<", t.render(ctxt, false), ">"], TField::Set(t) => seq!["preserves::value::Set<", t.render(ctxt, false), ">"],
TField::Map(k, v) => seq!["preserves::value::Map", TField::Map(k, v) => seq!["preserves::value::Map",
@ -192,29 +204,34 @@ impl TField {
v.render(ctxt, false)]], v.render(ctxt, false)]],
TField::Ref(r) => TField::Ref(r) =>
if box_needed { if box_needed {
seq!["std::boxed::Box", anglebrackets![ctxt.render_ref(r, true)]] seq!["std::boxed::Box", anglebrackets![
ctxt.render_ref(r, RefRenderStyle::Qualified)]]
} else { } else {
seq![ctxt.render_ref(r, true)] seq![ctxt.render_ref(r, RefRenderStyle::Qualified)]
}, },
TField::Base(n) => seq![n.to_owned()], TField::Base(n) => seq![n.to_owned()],
} }
} }
pub fn has_embedded(&self, ctxt: &ModuleContext, seen: &mut Set<Ref>) -> bool { pub fn has_embedded(&self, default_module_path: &ModulePath, ctxt: &BundleContext, seen: &mut Set<Ref>) -> bool {
match self { match self {
TField::Unit => false, TField::Unit => false,
TField::Any => true, // at least potentially true TField::Any => true, // at least potentially true
TField::Embedded => true, TField::Embedded => true,
TField::Array(f) => f.has_embedded(ctxt, seen), TField::Array(f) => f.has_embedded(default_module_path, ctxt, seen),
TField::Set(f) => f.has_embedded(ctxt, seen), TField::Set(f) => f.has_embedded(default_module_path, ctxt, seen),
TField::Map(k, v) => k.has_embedded(ctxt, seen) || v.has_embedded(ctxt, seen), TField::Map(k, v) =>
k.has_embedded(default_module_path, ctxt, seen) ||
v.has_embedded(default_module_path, ctxt, seen),
TField::Ref(r) => { TField::Ref(r) => {
let r = ctxt.qualify(r); let r = r.qualify(default_module_path);
if seen.contains(&r) { if seen.contains(&r) {
false false
} else { } else {
seen.insert(r.clone()); seen.insert(r.clone());
ctxt.type_for_name(&r).map(|ty| ty._has_embedded(ctxt, seen)).unwrap_or(false) ctxt.type_for_name(&r).map(|ty| ty._has_embedded(ctxt, seen)).unwrap_or(false)
// ^ TODO: should the "false" be configurable?
// cf. ModuleContext::ref_has_embedded.
} }
} }
TField::Base(_) => false, TField::Base(_) => false,
@ -237,17 +254,19 @@ impl TSimple {
}] }]
} }
pub fn has_embedded(&self, ctxt: &ModuleContext, seen: &mut Set<Ref>) -> bool { pub fn has_embedded(&self, default_module_path: &ModulePath, ctxt: &BundleContext, seen: &mut Set<Ref>) -> bool {
match self { match self {
TSimple::Field(f) => f.has_embedded(ctxt, seen), TSimple::Field(f) =>
TSimple::Record(TRecord(fs)) => fs.iter().any(|(_k, v)| v.has_embedded(ctxt, seen)), f.has_embedded(default_module_path, ctxt, seen),
TSimple::Record(TRecord(fs)) =>
fs.iter().any(|(_k, v)| v.has_embedded(default_module_path, ctxt, seen)),
} }
} }
} }
impl TDefinition { impl TDefinition {
pub fn generic_decl(&self, ctxt: &ModuleContext) -> Item { pub fn generic_decl(&self, ctxt: &ModuleContext) -> Item {
if self.has_embedded(ctxt) { if self.has_embedded(ctxt.bundle) {
ctxt.literals_generic_decls() ctxt.literals_generic_decls()
} else { } else {
item("") item("")
@ -255,7 +274,7 @@ impl TDefinition {
} }
pub fn generic_decl_with_defaults(&self, ctxt: &ModuleContext) -> Item { pub fn generic_decl_with_defaults(&self, ctxt: &ModuleContext) -> Item {
if self.has_embedded(ctxt) { if self.has_embedded(ctxt.bundle) {
ctxt.literals_generic_decls_with_defaults() ctxt.literals_generic_decls_with_defaults()
} else { } else {
item("") item("")
@ -263,7 +282,7 @@ impl TDefinition {
} }
pub fn generic_arg(&self, ctxt: &ModuleContext) -> Item { pub fn generic_arg(&self, ctxt: &ModuleContext) -> Item {
if self.has_embedded(ctxt) { if self.has_embedded(ctxt.bundle) {
ctxt.literals_generic_arg() ctxt.literals_generic_arg()
} else { } else {
item("") item("")
@ -273,25 +292,27 @@ impl TDefinition {
pub fn render(&self, ctxt: &ModuleContext, n: &str) -> impl Emittable { pub fn render(&self, ctxt: &ModuleContext, n: &str) -> impl Emittable {
vertical(false, seq![ vertical(false, seq![
"#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Hash)]", "#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Hash)]",
match self { match &self.body {
TDefinition::Union(items) => TDefinitionBody::Union(items) =>
seq!["pub enum ", seq!["pub enum ",
names::render_constructor(n), self.generic_decl_with_defaults(ctxt), " ", names::render_constructor(n), self.generic_decl_with_defaults(ctxt), " ",
vertical(false, braces(items.iter().map( vertical(false, braces(items.iter().map(
|(n, d)| item(d.render(ctxt, item(""), false, n))).collect()))], |(n, d)| item(d.render(ctxt, item(""), false, n))).collect()))],
TDefinition::Simple(s) => TDefinitionBody::Simple(s) =>
seq!["pub struct ", s.render(ctxt, self.generic_decl_with_defaults(ctxt), true, n)], seq!["pub struct ", s.render(ctxt, self.generic_decl_with_defaults(ctxt), true, n)],
}]) }])
} }
pub fn has_embedded(&self, ctxt: &ModuleContext) -> bool { pub fn has_embedded(&self, ctxt: &BundleContext) -> bool {
self._has_embedded(ctxt, &mut Set::new()) self._has_embedded(ctxt, &mut Set::new())
} }
fn _has_embedded(&self, ctxt: &ModuleContext, seen: &mut Set<Ref>) -> bool { fn _has_embedded(&self, ctxt: &BundleContext, seen: &mut Set<Ref>) -> bool {
match self { match &self.body {
TDefinition::Union(entries) => entries.iter().any(|(_k, v)| v.has_embedded(ctxt, seen)), TDefinitionBody::Union(entries) =>
TDefinition::Simple(t) => t.has_embedded(ctxt, seen), entries.iter().any(|(_k, v)| v.has_embedded(&self.self_ref.module, ctxt, seen)),
TDefinitionBody::Simple(t) =>
t.has_embedded(&self.self_ref.module, ctxt, seen),
} }
} }
} }

View File

@ -61,7 +61,7 @@ fn normal_src(src: String, is_struct: bool) -> ValueContext {
} }
pub fn gen_definition_unparser(m: &mut ModuleContext, n: &str, d: &Definition) { pub fn gen_definition_unparser(m: &mut ModuleContext, n: &str, d: &Definition) {
let ty = definition_type(d); let ty = definition_type(&m.module_path, n, d);
m.define_function( m.define_function(
n, n,
@ -97,17 +97,14 @@ pub fn gen_definition_unparser(m: &mut ModuleContext, n: &str, d: &Definition) {
} }
} }
let (topdecl, innerdecl) = if ty.has_embedded(ctxt.m) { item(seq!["impl", ctxt.m.literals_generic_decls(),
(ctxt.m.literals_generic_decls(), item("")) " _support::Unparse", anglebrackets![ctxt.m.literals_type(),
} else { ctxt.m.any_type()], " for ",
(item(""), ctxt.m.literals_generic_decls()) names::render_constructor(n), ty.generic_arg(ctxt.m), " ",
}; block![
seq!["fn unparse(&self, _ctxt: &", ctxt.m.literals_type(),
item(seq!["impl", topdecl, " ", ") -> ", ctxt.m.any_type(), " ",
names::render_constructor(n), ty.generic_arg(ctxt.m), " ", block![ block(body)]]])
seq!["pub fn unparse", innerdecl,
"(&self, _ctxt: ", ctxt.m.literals_type(), ") -> ",
ctxt.m.any_type(), " ", block(body)]]])
}); });
// m.define_function( // m.define_function(

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,12 @@ pub mod compiler;
pub mod support; pub mod support;
pub mod gen; pub mod gen;
pub use support::Codec;
pub use support::Deserialize;
pub use support::Parse;
pub use support::ParseError;
pub use support::Unparse;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#[test] #[test]
@ -32,6 +38,8 @@ mod tests {
#[test] #[test]
fn metaschema_parsing() -> Result<(), std::io::Error> { fn metaschema_parsing() -> Result<(), std::io::Error> {
use preserves::value::{BinarySource, IOBinarySource, Reader}; use preserves::value::{BinarySource, IOBinarySource, Reader};
use crate::Parse;
use crate::Unparse;
use crate::gen::schema::*; use crate::gen::schema::*;
let mut f = std::fs::File::open("../../../schema/schema.bin")?; let mut f = std::fs::File::open("../../../schema/schema.bin")?;

View File

@ -19,18 +19,46 @@ use std::sync::Arc;
use thiserror::Error; use thiserror::Error;
pub struct Codec<N: NestedValue, L: Default> { pub trait Parse<L, Value: NestedValue>: Sized {
fn parse(literals: &L, value: &Value) -> Result<Self, ParseError>;
}
impl<L, Value: NestedValue> Parse<L, Value> for Value {
fn parse(_literals: &L, value: &Value) -> Result<Self, ParseError> {
Ok(value.clone())
}
}
pub trait Unparse<L, Value: NestedValue> {
fn unparse(&self, literals: &L) -> Value;
}
impl<L, Value: NestedValue> Unparse<L, Value> for Value {
fn unparse(&self, _literals: &L) -> Value {
self.clone()
}
}
pub struct Codec<L: Default, N: NestedValue> {
pub literals: L, pub literals: L,
phantom: PhantomData<N>, phantom: PhantomData<N>,
} }
impl<N: NestedValue, L: Default> Codec<N, L> { impl<L: Default, N: NestedValue> Codec<L, N> {
pub fn new() -> Self { pub fn new() -> Self {
Codec { Codec {
literals: L::default(), literals: L::default(),
phantom: PhantomData, phantom: PhantomData,
} }
} }
pub fn parse<T: Parse<L, N>>(&self, value: &N) -> Result<T, ParseError> {
T::parse(&self.literals, value)
}
pub fn unparse<T: Unparse<L, N>>(&self, value: &T) -> N {
value.unparse(&self.literals)
}
} }
pub trait Deserialize<'de, N: NestedValue, R: Reader<'de, N>> pub trait Deserialize<'de, N: NestedValue, R: Reader<'de, N>>