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>),
}
pub enum RefRenderStyle {
Bare,
Qualified,
}
lazy_static! {
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> {
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 {
@ -138,7 +150,7 @@ impl<'m, 'b> ModuleContext<'m, 'b> {
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) {
None =>
if r.module.0.is_empty() {
@ -153,43 +165,32 @@ impl<'m, 'b> ModuleContext<'m, 'b> {
Some(s) =>
item(name![s.to_owned(), r.name.to_owned()])
};
if with_generic_args && self.ref_has_embedded(r) {
item(seq![base, anglebrackets!["_Any"]])
} else {
base
let q = self.ref_has_embedded(r);
match style {
RefRenderStyle::Bare =>
base,
RefRenderStyle::Qualified =>
if q { item(seq![base, anglebrackets!["_Value"]]) } else { base },
}
}
pub fn any_type(&self) -> &'static str {
"_Any"
}
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))
"_Value"
}
pub fn ref_has_embedded(&self, r: &Ref) -> bool {
match self.type_for_name(r) {
Some(ty) => ty.has_embedded(self),
None => false, // TODO: should this be configurable?
}
let r = r.qualify(&self.module_path);
self.bundle.type_for_name(&r).map(|ty| ty.has_embedded(self.bundle)).unwrap_or(false)
// ^ TODO: should the "false" be configurable?
}
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 {
item(anglebrackets![
seq!["_Any: preserves::value::NestedValue = ",
seq!["_Value: preserves::value::NestedValue = ",
if self.schema.embedded_type == EmbeddedTypeName::False {
"preserves::value::IOValue"
} else {
@ -198,11 +199,11 @@ impl<'m, 'b> ModuleContext<'m, 'b> {
}
pub fn literals_generic_arg(&self) -> Item {
item("<_Any>")
item("<_Value>")
}
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 {

View File

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

View File

@ -3,7 +3,10 @@ use crate::gen::schema::*;
use crate::syntax::block::Item;
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::types::*;
@ -19,7 +22,7 @@ impl compiler::Plugin for ParserPlugin {
}
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(
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);
construct(&ctxt, ctorname, false, &pattern_type(pat), dest, &mut body);
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<",
names::render_constructor(n), ty.generic_arg(ctxt.m),
", _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) {
(ctxt.m.literals_generic_decls(), item(""))
} else {
(item(""), ctxt.m.literals_generic_decls())
};
item(seq!["impl", topdecl, " ",
item(seq!["impl", ctxt.m.literals_generic_decls(),
" _support::Parse", anglebrackets![ctxt.m.literals_type(),
ctxt.m.any_type()], " for ",
names::render_constructor(n), ty.generic_arg(ctxt.m), " ",
block![
seq!["pub fn parse", innerdecl, "(_ctxt: ", ctxt.m.literals_type(),
seq!["fn parse(_ctxt: &", ctxt.m.literals_type(),
", value: &", ctxt.m.any_type(), ") -> ",
"std::result::Result<Self, _support::ParseError> ",
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(
@ -214,7 +197,7 @@ fn simple_pattern_parser(
dest
},
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,
&dest,
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::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::types::*;
@ -75,7 +78,7 @@ impl BoundaryTracker {
}
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(
n,
@ -100,8 +103,8 @@ pub fn gen_definition_reader(m: &mut ModuleContext, n: &str, d: &Definition) {
item(seq![
"fn ", fname.clone(), anglebrackets![
"'de",
"_Any: preserves::value::NestedValue",
"R: _support::Reader<'de, _Any>"],
"_Value: preserves::value::NestedValue",
"R: _support::Reader<'de, _Value>"],
"(r: &mut R) -> ",
"std::result::Result<",
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![
"impl", anglebrackets!["'de",
"_Any: preserves::value::NestedValue",
"R: _support::Reader<'de, _Any>"], " ",
"_support::Deserialize", anglebrackets!["'de", "_Any", "R"], " ",
"_Value: preserves::value::NestedValue",
"R: _support::Reader<'de, _Value>"], " ",
"_support::Deserialize", anglebrackets!["'de", "_Value", "R"], " ",
"for ", names::render_constructor(n), ty.generic_arg(ctxt.m), " ", block![
seq!["fn deserialize(r: &mut R) -> ",
"std::result::Result<Self, _support::ParseError> ",
@ -426,7 +429,7 @@ fn simple_pattern_reader(
dest
},
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)?"]));
dest
},

View File

@ -5,13 +5,22 @@ use crate::gen::schema::*;
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;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum TDefinition {
Union(Vec<(String, TSimple)>),
Simple(TSimple),
pub struct TDefinition {
pub self_ref: Ref,
pub body: TDefinitionBody,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum TDefinitionBody {
Union(Vec<(String, TSimple)>),
Simple(TSimple),
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
@ -42,7 +51,7 @@ impl compiler::Plugin for TypePlugin {
fn generate_module(&self, m: &mut ModuleContext) {
if let EmbeddedTypeName::Ref(r) = &m.schema.embedded_type {
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 _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) {
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(seq![
"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 {
match d {
Definition::Or { pattern_0, pattern_1, pattern_n } =>
TDefinition::Union(or_definition_type(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)),
Definition::Pattern(p) =>
TDefinition::Simple(pattern_type(p)),
pub fn definition_type(module: &ModulePath, n: &str, d: &Definition) -> TDefinition {
TDefinition {
self_ref: Ref { module: module.clone(), name: n.to_owned() },
body: match d {
Definition::Or { 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 } =>
TDefinitionBody::Simple(and_definition_type(pattern_0, pattern_1, pattern_n)),
Definition::Pattern(p) =>
TDefinitionBody::Simple(pattern_type(p)),
}
}
}
@ -183,8 +195,8 @@ impl TField {
fn render(&self, ctxt: &ModuleContext, box_needed: bool) -> impl Emittable {
match self {
TField::Unit => seq!["()"],
TField::Any => seq!["_Any"],
TField::Embedded => seq!["_Ptr"],
TField::Any => seq!["_Value"],
TField::Embedded => seq!["_Value::D"],
TField::Array(t) => seq!["std::vec::Vec<", t.render(ctxt, false), ">"],
TField::Set(t) => seq!["preserves::value::Set<", t.render(ctxt, false), ">"],
TField::Map(k, v) => seq!["preserves::value::Map",
@ -192,29 +204,34 @@ impl TField {
v.render(ctxt, false)]],
TField::Ref(r) =>
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 {
seq![ctxt.render_ref(r, true)]
seq![ctxt.render_ref(r, RefRenderStyle::Qualified)]
},
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 {
TField::Unit => false,
TField::Any => true, // at least potentially true
TField::Embedded => true,
TField::Array(f) => f.has_embedded(ctxt, seen),
TField::Set(f) => f.has_embedded(ctxt, seen),
TField::Map(k, v) => k.has_embedded(ctxt, seen) || v.has_embedded(ctxt, seen),
TField::Array(f) => f.has_embedded(default_module_path, ctxt, seen),
TField::Set(f) => f.has_embedded(default_module_path, 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) => {
let r = ctxt.qualify(r);
let r = r.qualify(default_module_path);
if seen.contains(&r) {
false
} else {
seen.insert(r.clone());
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,
@ -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 {
TSimple::Field(f) => f.has_embedded(ctxt, seen),
TSimple::Record(TRecord(fs)) => fs.iter().any(|(_k, v)| v.has_embedded(ctxt, seen)),
TSimple::Field(f) =>
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 {
pub fn generic_decl(&self, ctxt: &ModuleContext) -> Item {
if self.has_embedded(ctxt) {
if self.has_embedded(ctxt.bundle) {
ctxt.literals_generic_decls()
} else {
item("")
@ -255,7 +274,7 @@ impl TDefinition {
}
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()
} else {
item("")
@ -263,7 +282,7 @@ impl TDefinition {
}
pub fn generic_arg(&self, ctxt: &ModuleContext) -> Item {
if self.has_embedded(ctxt) {
if self.has_embedded(ctxt.bundle) {
ctxt.literals_generic_arg()
} else {
item("")
@ -273,25 +292,27 @@ impl TDefinition {
pub fn render(&self, ctxt: &ModuleContext, n: &str) -> impl Emittable {
vertical(false, seq![
"#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Hash)]",
match self {
TDefinition::Union(items) =>
match &self.body {
TDefinitionBody::Union(items) =>
seq!["pub enum ",
names::render_constructor(n), self.generic_decl_with_defaults(ctxt), " ",
vertical(false, braces(items.iter().map(
|(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)],
}])
}
pub fn has_embedded(&self, ctxt: &ModuleContext) -> bool {
pub fn has_embedded(&self, ctxt: &BundleContext) -> bool {
self._has_embedded(ctxt, &mut Set::new())
}
fn _has_embedded(&self, ctxt: &ModuleContext, seen: &mut Set<Ref>) -> bool {
match self {
TDefinition::Union(entries) => entries.iter().any(|(_k, v)| v.has_embedded(ctxt, seen)),
TDefinition::Simple(t) => t.has_embedded(ctxt, seen),
fn _has_embedded(&self, ctxt: &BundleContext, seen: &mut Set<Ref>) -> bool {
match &self.body {
TDefinitionBody::Union(entries) =>
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) {
let ty = definition_type(d);
let ty = definition_type(&m.module_path, n, d);
m.define_function(
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) {
(ctxt.m.literals_generic_decls(), item(""))
} else {
(item(""), ctxt.m.literals_generic_decls())
};
item(seq!["impl", topdecl, " ",
names::render_constructor(n), ty.generic_arg(ctxt.m), " ", block![
seq!["pub fn unparse", innerdecl,
"(&self, _ctxt: ", ctxt.m.literals_type(), ") -> ",
ctxt.m.any_type(), " ", block(body)]]])
item(seq!["impl", ctxt.m.literals_generic_decls(),
" _support::Unparse", anglebrackets![ctxt.m.literals_type(),
ctxt.m.any_type()], " for ",
names::render_constructor(n), ty.generic_arg(ctxt.m), " ",
block![
seq!["fn unparse(&self, _ctxt: &", ctxt.m.literals_type(),
") -> ", ctxt.m.any_type(), " ",
block(body)]]])
});
// 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 gen;
pub use support::Codec;
pub use support::Deserialize;
pub use support::Parse;
pub use support::ParseError;
pub use support::Unparse;
#[cfg(test)]
mod tests {
#[test]
@ -32,6 +38,8 @@ mod tests {
#[test]
fn metaschema_parsing() -> Result<(), std::io::Error> {
use preserves::value::{BinarySource, IOBinarySource, Reader};
use crate::Parse;
use crate::Unparse;
use crate::gen::schema::*;
let mut f = std::fs::File::open("../../../schema/schema.bin")?;

View File

@ -19,18 +19,46 @@ use std::sync::Arc;
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,
phantom: PhantomData<N>,
}
impl<N: NestedValue, L: Default> Codec<N, L> {
impl<L: Default, N: NestedValue> Codec<L, N> {
pub fn new() -> Self {
Codec {
literals: L::default(),
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>>