Massive refactor to be more flexible around embedded types

This commit is contained in:
Tony Garnock-Jones 2021-09-15 10:43:31 +02:00
parent 8127033407
commit 352d8ba1b3
11 changed files with 1171 additions and 793 deletions

View File

@ -8,6 +8,7 @@ use convert_case::{Case, Casing};
use lazy_static::lazy_static;
use preserves::value::IOValue;
use preserves::value::Map;
use preserves::value::NestedValue;
use preserves::value::Value;
@ -16,25 +17,31 @@ use super::CompilerConfig;
use super::names;
use super::types;
#[derive(Clone, Copy)]
pub enum ModuleContextMode {
TargetIOValue,
TargetAny,
pub struct BundleContext<'b> {
pub config: &'b CompilerConfig,
pub types: Map<Ref, types::TDefinition>,
pub literals: Map<IOValue, String>,
}
pub struct ModuleContext<'m> {
#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
pub enum ModuleContextMode {
TargetModule,
TargetToplevel,
TargetGeneric,
}
pub struct ModuleContext<'m, 'b> {
pub bundle: &'m mut BundleContext<'b>,
pub module_path: ModulePath,
pub config: &'m CompilerConfig,
pub literals: Map<_Any, String>,
pub schema: &'m Schema,
pub typedefs: Vec<Item>,
pub functiondefs: Vec<Item>,
pub mode: Option<ModuleContextMode>,
pub schema: &'m Schema,
pub mode: ModuleContextMode,
}
pub struct FunctionContext<'a, 'm> {
pub struct FunctionContext<'a, 'm, 'b> {
pub error_context: String,
pub m: &'a mut ModuleContext<'m>,
pub m: &'a mut ModuleContext<'m, 'b>,
pub temp_counter: usize,
pub captures: Vec<Capture>,
pub capture_mode: CaptureMode,
@ -55,24 +62,22 @@ lazy_static! {
static ref ID_RE: regex::Regex = regex::Regex::new(r"^[a-zA-Z][a-zA-Z_0-9]*$").unwrap();
}
impl<'m> ModuleContext<'m> {
impl<'b> BundleContext<'b> {
pub fn new(
config: &'m CompilerConfig,
module_path: &ModulePath,
schema: &'m Schema,
config: &'b CompilerConfig,
) -> Self {
ModuleContext {
module_path: module_path.to_owned(),
BundleContext {
config,
types: config.build_type_cache(),
literals: Map::new(),
typedefs: Vec::new(),
functiondefs: Vec::new(),
mode: None,
schema,
}
}
pub fn define_literal(&mut self, v: &_Any) -> String {
pub fn type_for_name(&self, r: &Ref) -> &types::TDefinition {
self.types.get(r).unwrap_or_else(|| panic!("{:?} not found", r))
}
pub fn define_literal(&mut self, v: &IOValue) -> String {
let prefix = format!("LIT_{}", self.literals.len());
let next_id = match v.value() {
Value::Boolean(b) => prefix + "_" + &b.to_string(),
@ -82,7 +87,46 @@ impl<'m> ModuleContext<'m> {
_ => prefix
};
let next_id = next_id.to_case(Case::UpperSnake);
"&*".to_owned() + self.target_prefix() + "::" + self.literals.entry(v.clone()).or_insert(next_id)
format!("&_ctxt.{}", self.literals.entry(v.clone()).or_insert(next_id))
}
pub fn generate_module<F: FnOnce(&mut ModuleContext)>(
&mut self,
path: &Vec<String>,
schema: &Schema,
mode: ModuleContextMode,
items: &mut Map<ModuleContextMode, Vec<Item>>,
f: F,
) {
let mut m = ModuleContext::new(self, &ModulePath(path.clone()), schema, mode);
f(&mut m);
items.entry(mode).or_default().extend(m.extract());
}
}
impl<'m, 'b> ModuleContext<'m, 'b> {
pub fn new(
bundle: &'m mut BundleContext<'b>,
module_path: &ModulePath,
schema: &'m Schema,
mode: ModuleContextMode,
) -> Self {
ModuleContext {
bundle,
module_path: module_path.to_owned(),
schema,
typedefs: Vec::new(),
functiondefs: Vec::new(),
mode,
}
}
pub fn reset_mode(&mut self) {
self.mode = ModuleContextMode::TargetToplevel;
}
pub fn define_literal(&mut self, v: &IOValue) -> String {
self.bundle.define_literal(v)
}
pub fn define_type(&mut self, i: Item) {
@ -94,44 +138,79 @@ impl<'m> ModuleContext<'m> {
self.functiondefs.push(i)
}
pub fn render_ref(&self, r: &Ref) -> Item {
match self.config.module_aliases.get(&r.module.0) {
pub fn render_ref(&self, r: &Ref, with_generic_args: bool) -> Item {
let base = match self.bundle.config.module_aliases.get(&r.module.0) {
None =>
if r.module.0.is_empty() {
item(r.name.to_owned())
} else {
let mut items = Vec::new();
items.push(item(self.config.fully_qualified_module_prefix.to_owned()));
items.push(item(self.bundle.config.fully_qualified_module_prefix.to_owned()));
for p in &r.module.0 { items.push(item(names::render_modname(p))) }
items.push(item(r.name.to_owned()));
item(name(items))
}
Some(s) =>
item(name![s.to_owned(), r.name.to_owned()])
};
if with_generic_args && self.type_for_name(r).has_embedded(self) {
item(seq![base, anglebrackets!["_Any"]])
} else {
base
}
}
pub fn mode(&self) -> ModuleContextMode {
self.mode.expect("defined ModuleContextMode")
pub fn any_type(&self) -> &'static str {
"_Any"
}
pub fn target(&self) -> &'static str {
match self.mode() {
ModuleContextMode::TargetIOValue => "preserves::value::IOValue",
ModuleContextMode::TargetAny => "_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 target_prefix(&self) -> &'static str {
match self.mode() {
ModuleContextMode::TargetIOValue => "_io_",
ModuleContextMode::TargetAny => "_any_",
}
pub fn type_for_name(&self, r: &Ref) -> &types::TDefinition {
self.bundle.type_for_name(&self.qualify(r))
}
pub fn literals_generic_decls(&self) -> Item {
item(anglebrackets!["_Any: preserves::value::NestedValue"])
}
pub fn literals_generic_decls_with_defaults(&self) -> Item {
item(anglebrackets![
seq!["_Any: preserves::value::NestedValue = ",
if self.schema.embedded_type == EmbeddedTypeName::False {
"preserves::value::IOValue"
} else {
"_Any"
}]])
}
pub fn literals_generic_arg(&self) -> Item {
item("<_Any>")
}
pub fn literals_type(&self) -> Item {
item(seq!["&", self.literals_base_type(), self.literals_generic_arg()])
}
pub fn literals_base_type(&self) -> Item {
item(format!("{}::Literals", self.bundle.config.fully_qualified_module_prefix))
}
pub fn extract(&mut self) -> Vec<Item> {
let mut items = std::mem::take(&mut self.typedefs);
items.extend(std::mem::take(&mut self.functiondefs));
items
}
}
impl<'a, 'm> FunctionContext<'a, 'm> {
pub fn new(m: &'a mut ModuleContext<'m>, error_context: &str) -> Self {
impl<'a, 'm, 'b> FunctionContext<'a, 'm, 'b> {
pub fn new(m: &'a mut ModuleContext<'m, 'b>, error_context: &str) -> Self {
FunctionContext {
error_context: error_context.to_owned(),
m: m,

View File

@ -6,8 +6,10 @@ pub mod types;
pub mod unparsers;
use crate::*;
use crate::compiler::context::*;
use crate::gen::Literals;
use crate::gen::schema::*;
use crate::syntax::block::Formatter;
use crate::syntax::block::{Formatter, Item};
use crate::syntax::block::constructors::*;
use glob::glob;
@ -15,13 +17,10 @@ use preserves::value::BinarySource;
use preserves::value::IOBinarySource;
use preserves::value::Map;
use preserves::value::Reader;
use preserves::value::Set;
use std::convert::TryFrom;
use std::fs::DirBuilder;
use std::fs::File;
use std::io;
use std::io::BufRead;
use std::io::Read;
use std::io::Write;
use std::path::PathBuf;
@ -29,9 +28,11 @@ use std::path::PathBuf;
pub type ModulePath = Vec<String>;
pub trait Plugin: std::fmt::Debug {
fn generate(
fn generate_module(&self, _module_ctxt: &mut ModuleContext) {}
fn generate_definition(
&self,
module_ctxt: &mut context::ModuleContext,
module_ctxt: &mut ModuleContext,
definition_name: &str,
definition: &Definition,
);
@ -73,8 +74,9 @@ impl CompilerConfig {
let mut src = IOBinarySource::new(&mut f);
let mut reader = src.packed_iovalues();
let blob = reader.demand_next(false)?;
let literals = Literals::default();
if let Ok(s) = Schema::try_from(&blob) {
if let Ok(s) = Schema::parse(&literals, &blob) {
let prefix = i.file_stem().ok_or_else(
|| io::Error::new(io::ErrorKind::InvalidData,
format!("Bad schema file stem: {:?}", i)))?
@ -85,7 +87,7 @@ impl CompilerConfig {
continue;
}
if let Ok(Bundle { modules }) = Bundle::try_from(&blob) {
if let Ok(Bundle { modules }) = Bundle::parse(&literals, &blob) {
for (ModulePath(k), v) in modules.0 {
self.bundle.insert(k, v);
}
@ -97,6 +99,31 @@ impl CompilerConfig {
}
Ok(())
}
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()
}
fn generate_definition(
&self,
b: &mut BundleContext,
k: &ModulePath,
v: &Schema,
n: &str,
d: &Definition,
mode: ModuleContextMode,
generated: &mut Map<ModuleContextMode, Vec<Item>>,
) {
b.generate_module(k, v, mode, generated, |m| {
for plugin in self.plugins.iter() {
plugin.generate_definition(m, n, d);
}
});
}
}
pub fn expand_inputs(globs: &Vec<String>) -> io::Result<Vec<PathBuf>> {
@ -130,6 +157,8 @@ impl Schema {
}
pub fn compile(config: &CompilerConfig) -> io::Result<()> {
let mut b = BundleContext::new(config);
for (k, v) in config.bundle.iter() {
let mut output_path = config.output_dir.clone();
output_path.extend(k);
@ -137,102 +166,106 @@ pub fn compile(config: &CompilerConfig) -> io::Result<()> {
let module_name = names::render_modname(&module_name);
output_path.set_file_name(format!("{}.rs", module_name));
DirBuilder::new().recursive(true).create(output_path.parent().unwrap())?;
let mut m = context::ModuleContext::new(config, &ModulePath(k.clone()), v);
let mut modes: Vec<context::ModuleContextMode> =
vec![context::ModuleContextMode::TargetAny];
//---------------------------------------------------------------------------
match &v.embedded_type {
EmbeddedTypeName::False => {
m.define_type(item(seq!["pub type _Ptr = preserves::value::IOValue;"]));
m.define_type(item(seq!["pub type _Any = preserves::value::IOValue;"]));
let mut generated = Map::new();
b.generate_module(k, v, ModuleContextMode::TargetModule, &mut generated, |m| {
for plugin in config.plugins.iter() {
plugin.generate_module(m);
}
EmbeddedTypeName::Ref(r) => {
modes.push(context::ModuleContextMode::TargetIOValue);
m.define_type(item(seq!["pub type _Dom = ", m.render_ref(&**r), ";"]));
m.define_type(item(seq!["pub type _Ptr = std::sync::Arc<_Dom>;"]));
m.define_type(item(seq!["pub type _Any = preserves::value::ArcValue<_Ptr>;"]));
}
}
let modes = modes; // rebind as non-mutable
});
for (n, d) in &v.definitions.0 {
for plugin in config.plugins.iter() {
plugin.generate(&mut m, n, d);
}
for mode in &modes {
m.mode = Some(*mode);
for plugin in config.plugins.iter() {
plugin.generate(&mut m, n, d);
}
}
m.mode = None;
use ModuleContextMode::*;
config.generate_definition(&mut b, k, v, n, d, TargetToplevel, &mut generated);
config.generate_definition(&mut b, k, v, n, d, TargetGeneric, &mut generated);
}
//---------------------------------------------------------------------------
let mut lines: Vec<String> = Vec::new();
lines.push("#![allow(unused_parens)]".to_owned());
lines.push("#![allow(unused_imports)]".to_owned());
lines.push("".to_owned());
lines.push("use std::convert::TryFrom;".to_owned());
lines.push(format!("use {}::support as _support;", &config.support_crate));
lines.push("use _support::Deserialize;".to_owned());
lines.push("use _support::preserves;".to_owned());
lines.push("use preserves::value::Domain;".to_owned());
lines.push("use preserves::value::NestedValue;".to_owned());
lines.push("".to_owned());
lines.push(Formatter::to_string(vertical(false, seq![
"#![allow(unused_parens)]",
"#![allow(unused_imports)]",
"",
"use std::convert::TryFrom;",
format!("use {}::support as _support;", &config.support_crate),
"use _support::Deserialize;",
"use _support::preserves;",
"use preserves::value::Domain;",
"use preserves::value::NestedValue;",
""])));
for mode in &modes {
m.mode = Some(*mode);
lines.push(format!("mod {} {{", m.target_prefix()));
lines.push(" use super::_Any;".to_owned());
lines.push(format!(" use {}::support as _support;", &config.support_crate));
lines.push(" _support::lazy_static! {".to_owned());
for (value, name) in &m.literals {
let bs = preserves::value::PackedWriter::encode_iovalue(&value).unwrap();
lines.push(format!(
" pub static ref {}: {} = /* {:?} */ _support::decode_lit(&vec!{:?}).unwrap();",
name,
m.target(),
value,
bs));
let mut emit_items = |items: Vec<Item>| {
if !items.is_empty() {
lines.push(Formatter::to_string(vertical(true, seq(items))));
lines.push("".to_owned());
}
lines.push(" }".to_owned());
lines.push("}".to_owned());
lines.push("".to_owned());
}
m.mode = None;
};
emit_items(generated.remove(&ModuleContextMode::TargetModule).unwrap());
emit_items(generated.remove(&ModuleContextMode::TargetToplevel).unwrap());
emit_items(generated.remove(&ModuleContextMode::TargetGeneric).unwrap());
for i in m.typedefs {
lines.push(Formatter::to_string(i));
lines.push("".to_owned());
}
for i in m.functiondefs {
lines.push(Formatter::to_string(i));
lines.push("".to_owned());
}
// let mut generic_mod_items: Vec<Item> = vec![
// item(vertical(false, seq![
// format!("use {}::support as _support;", &config.support_crate),
// "use _support::Deserialize;",
// "use _support::preserves;"])),
// ];
// generic_mod_items.extend(generated.remove(&ModuleContextMode::TargetGeneric).unwrap());
//
// lines.push(Formatter::to_string(seq!["mod __ ", vertical(true, block(generic_mod_items))]));
// lines.push("".to_owned());
{
let contents = lines.join("\n");
write_if_changed(&output_path, contents.as_bytes())?;
}
{
let mut mod_rs = output_path.clone();
mod_rs.set_file_name("mod.rs");
let mut lines = if !mod_rs.exists() {
Set::new()
} else {
io::BufReader::new(File::open(&mod_rs)?)
.lines().collect::<Result<Set<String>, _>>()?
};
lines.insert(format!("pub mod {};", &module_name));
let contents = lines.into_iter().collect::<Vec<String>>().join("\n");
write_if_changed(&mod_rs, contents.as_bytes())?;
}
}
{
let mut mod_rs = config.output_dir.clone();
mod_rs.extend(vec!["mod.rs"]);
let mut lines = Vec::new();
for modpath in config.bundle.keys() {
lines.push(format!("pub mod {};", names::render_modname(modpath.last().unwrap())));
}
lines.push("".to_owned());
lines.push(format!("use {}::support as _support;", &config.support_crate));
lines.push("use _support::preserves;".to_owned());
lines.push("".to_owned());
lines.push("#[allow(non_snake_case)]".to_owned());
lines.push(Formatter::to_string(item(seq![
"pub struct Literals", anglebrackets!["N: preserves::value::NestedValue"], " ",
vertical(false, braces(b.literals.iter().map(
|(value, name)| item(format!("pub {}: N /* {:?} */", name, value))).collect()))
])));
lines.push("".to_owned());
lines.push(Formatter::to_string(item(seq![
"impl", anglebrackets!["N: preserves::value::NestedValue"],
" Default for Literals<N> ", block![
seq!["fn default() -> Self ", block![
seq!["Literals ", vertical(false, braces(b.literals.iter().map(|(value, name)| {
let bs = preserves::value::PackedWriter::encode_iovalue(&value).unwrap();
item(format!("{}: /* {:?} */ _support::decode_lit(&vec!{:?}).unwrap()",
name,
value,
bs))
}).collect()))]
]]
]
])));
lines.push("".to_owned());
let contents = lines.join("\n");
write_if_changed(&mod_rs, contents.as_bytes())?;
}
Ok(())
}

View File

@ -11,14 +11,16 @@ use super::types::*;
pub struct ParserPlugin;
impl compiler::Plugin for ParserPlugin {
fn generate(&self, module_ctxt: &mut ModuleContext, definition_name: &str, definition: &Definition) {
if module_ctxt.mode.is_some() {
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)
}
}
}
pub fn gen_definition_parser(m: &mut ModuleContext, n: &str, d: &Definition) {
let ty = definition_type(d);
m.define_function(
n,
|mut ctxt| {
@ -29,8 +31,7 @@ pub fn gen_definition_parser(m: &mut ModuleContext, n: &str, d: &Definition) {
let mut ps = vec![&**pattern_0, &**pattern_1];
ps.extend(pattern_n);
for NamedAlternative { variant_label: name, pattern: pat } in ps {
let fname = seq![ctxt.m.target_prefix(), "parse_",
names::render_fieldname(n), "_", names::render_fieldname(name)];
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),
@ -39,11 +40,14 @@ pub fn gen_definition_parser(m: &mut ModuleContext, n: &str, d: &Definition) {
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);
item(seq!["fn ", fname.clone(), "(value: &", ctxt.m.target(), ") -> ",
"std::result::Result<", names::render_constructor(n), ", _support::ParseError> ",
block(body)])
item(seq!["fn ", fname.clone(), ctxt.m.literals_generic_decls(),
"(_ctxt: ", ctxt.m.literals_type(), ", 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, "(value) { return Ok(r); }"]));
body.push(item(seq!["if let Ok(r) = ", fname, "(_ctxt, value) { return Ok(r); }"]));
}
body.push(item(seq![ctxt.err_code()]));
}
@ -62,13 +66,36 @@ pub fn gen_definition_parser(m: &mut ModuleContext, n: &str, d: &Definition) {
}
}
item(seq!["impl std::convert::TryFrom", anglebrackets![seq!["&", ctxt.m.target()]], " for ",
names::render_constructor(n), " ", block![
seq!["type Error = _support::ParseError;"],
seq!["fn try_from(value: &", ctxt.m.target(), ") -> ",
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 parse", innerdecl, "(_ctxt: ", ctxt.m.literals_type(),
", value: &", ctxt.m.any_type(), ") -> ",
"std::result::Result<Self, _support::ParseError> ",
block(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(
@ -118,12 +145,7 @@ fn simple_pattern_parser(
let dest = ctxt.gentempname();
match p {
SimplePattern::Any => {
match ctxt.m.mode() {
ModuleContextMode::TargetIOValue =>
ctxt.define_atom(body, &dest, item(seq!["_support::decode_embedded", parens![src.to_owned()], "?"])),
ModuleContextMode::TargetAny =>
ctxt.define_atom(body, &dest, item(src.to_owned())),
}
ctxt.define_atom(body, &dest, item(src.to_owned()));
dest
},
SimplePattern::Atom { atom_kind: k } => {
@ -140,16 +162,8 @@ fn simple_pattern_parser(
dest
},
SimplePattern::Embedded { .. } => {
match ctxt.m.mode() {
ModuleContextMode::TargetIOValue =>
ctxt.define_atom(body, &dest, item(seq![
"std::sync::Arc::new(_Dom::try_from",
parens![seq![src.to_owned(), ".value().to_embedded()?"]],
"?)"])),
ModuleContextMode::TargetAny =>
ctxt.define_atom(body, &dest, item(seq![
parens![seq![src.to_owned(), ".value().to_embedded()?"]]])),
}
ctxt.define_atom(body, &dest, item(seq![
parens![seq![src.to_owned(), ".value().to_embedded()?"]]]));
dest
},
SimplePattern::Lit { value } => {
@ -200,10 +214,10 @@ fn simple_pattern_parser(
dest
},
SimplePattern::Ref(r) => {
let tf = name![ctxt.m.render_ref(&**r), "try_from"];
let tf = name![ctxt.m.render_ref(&**r, false), "parse"];
ctxt.define_atom(body,
&dest,
item(seq![tf, parens![seq![src.to_owned()]], "?"]));
item(seq![tf, parens!["_ctxt", src.to_owned()], "?"]));
dest
},
}

View File

@ -7,10 +7,11 @@ use crate::syntax::block::constructors::*;
use preserves::value::AtomClass;
use preserves::value::CompoundClass;
use preserves::value::IOValue;
use preserves::value::NestedValue;
use preserves::value::ValueClass;
use super::context::{ModuleContext, FunctionContext};
use super::context::{ModuleContextMode, ModuleContext, FunctionContext};
use super::names;
use super::types::*;
@ -18,8 +19,8 @@ use super::types::*;
pub struct ReaderPlugin;
impl compiler::Plugin for ReaderPlugin {
fn generate(&self, module_ctxt: &mut ModuleContext, definition_name: &str, definition: &Definition) {
if module_ctxt.mode.is_none() {
fn generate_definition(&self, module_ctxt: &mut ModuleContext, definition_name: &str, definition: &Definition) {
if let ModuleContextMode::TargetGeneric = module_ctxt.mode {
gen_definition_reader(module_ctxt, definition_name, definition)
}
}
@ -74,6 +75,8 @@ impl BoundaryTracker {
}
pub fn gen_definition_reader(m: &mut ModuleContext, n: &str, d: &Definition) {
let ty = definition_type(d);
m.define_function(
n,
|mut ctxt| {
@ -97,9 +100,12 @@ 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>"],
"(r: &mut R) -> ",
"std::result::Result<", names::render_constructor(n), ", _support::ParseError> ",
"std::result::Result<",
names::render_constructor(n), ty.generic_arg(ctxt.m),
", _support::ParseError> ",
block(body)])
});
body.push(item(seq![
@ -132,9 +138,11 @@ pub fn gen_definition_reader(m: &mut ModuleContext, n: &str, d: &Definition) {
}
item(seq![
"impl", anglebrackets!["'de", "R: _support::Reader<'de, _Any>"], " ",
"impl", anglebrackets!["'de",
"_Any: preserves::value::NestedValue",
"R: _support::Reader<'de, _Any>"], " ",
"_support::Deserialize", anglebrackets!["'de", "_Any", "R"], " ",
"for ", names::render_constructor(n), " ", block![
"for ", names::render_constructor(n), ty.generic_arg(ctxt.m), " ", block![
seq!["fn deserialize(r: &mut R) -> ",
"std::result::Result<Self, _support::ParseError> ",
block(body)]]])
@ -207,8 +215,8 @@ where
}
type LiteralContinuation = Box<dyn FnOnce(&mut FunctionContext, &mut Vec<Item>) -> ()>;
type LiteralCases = Vec<(_Any, LiteralContinuation)>;
type LiteralSeqCases = Vec<(Vec<_Any>, LiteralContinuation)>;
type LiteralCases = Vec<(IOValue, LiteralContinuation)>;
type LiteralSeqCases = Vec<(Vec<IOValue>, LiteralContinuation)>;
fn read_expected_literal_seqs(
ctxt: &mut FunctionContext,
@ -418,7 +426,7 @@ fn simple_pattern_reader(
dest
},
SimplePattern::Ref(r) => {
let tf = name![ctxt.m.render_ref(&**r), "deserialize"];
let tf = name![ctxt.m.render_ref(&**r, false), "deserialize"];
ctxt.define_atom(body, &dest, item(seq![tf, "(r)?"]));
dest
},

View File

@ -1,9 +1,11 @@
use crate::*;
use crate::syntax::block::Emittable;
use crate::syntax::block::{Item, Emittable};
use crate::syntax::block::constructors::*;
use crate::gen::schema::*;
use super::context::ModuleContext;
use preserves::value::Set;
use super::context::{ModuleContextMode, ModuleContext};
use super::names;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
@ -37,11 +39,23 @@ pub struct TRecord(pub Vec<(String, TField)>);
pub struct TypePlugin;
impl compiler::Plugin for TypePlugin {
fn generate(&self, m: &mut ModuleContext, n: &str, d: &Definition) {
if m.mode.is_none() {
m.define_type(item(render_definition_type(m, n, &definition_type(d))));
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 _Ptr = std::sync::Arc<_Dom>;"],
seq!["pub type _Any = preserves::value::ArcValue<_Ptr>;"]
])));
}
}
fn generate_definition(&self, m: &mut ModuleContext, n: &str, d: &Definition) {
if let ModuleContextMode::TargetGeneric = m.mode {
let ty = definition_type(d);
m.define_type(item(ty.render(m, n)));
m.define_type(item(seq![
"impl preserves::value::Domain for ", names::render_constructor(n), " {}"]));
"impl", ty.generic_decl(m), " preserves::value::Domain for ",
names::render_constructor(n), ty.generic_arg(m), " {}"]));
}
}
}
@ -165,59 +179,119 @@ pub fn field_type(p: &SimplePattern) -> TField {
}
}
pub fn render_field_type(
ctxt: &ModuleContext,
box_needed: bool,
t: &TField,
) -> impl Emittable {
match t {
TField::Unit => seq!["()"],
TField::Any => seq!["_Any"],
TField::Embedded => seq!["_Ptr"],
TField::Array(t) => seq!["std::vec::Vec<", render_field_type(ctxt, false, t), ">"],
TField::Set(t) => seq!["preserves::value::Set<", render_field_type(ctxt, false, t), ">"],
TField::Map(k, v) => seq!["preserves::value::Map",
anglebrackets![render_field_type(ctxt, false, k),
render_field_type(ctxt, false, v)]],
TField::Ref(r) =>
if box_needed {
seq!["std::boxed::Box", anglebrackets![ctxt.render_ref(r)]]
} else {
seq![ctxt.render_ref(r)]
},
TField::Base(n) => seq![n.to_owned()],
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::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",
anglebrackets![k.render(ctxt, false),
v.render(ctxt, false)]],
TField::Ref(r) =>
if box_needed {
seq!["std::boxed::Box", anglebrackets![ctxt.render_ref(r, true)]]
} else {
seq![ctxt.render_ref(r, true)]
},
TField::Base(n) => seq![n.to_owned()],
}
}
pub fn has_embedded(&self, ctxt: &ModuleContext, 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::Ref(r) => {
let r = ctxt.qualify(r);
if seen.contains(&r) {
false
} else {
seen.insert(r.clone());
ctxt.type_for_name(&r)._has_embedded(ctxt, seen)
}
}
TField::Base(_) => false,
}
}
}
pub fn render_recordlike_type(
ctxt: &ModuleContext,
is_struct: bool,
n: &str,
d: &TSimple,
) -> impl Emittable {
let semi = if is_struct { seq![";"] } else { seq![] };
let ppub = if is_struct { "pub " } else { "" };
seq![names::render_constructor(n), match d {
TSimple::Record(TRecord(fs)) => seq![" ", braces(
fs.iter().map(|(n, d)| item(
seq![ppub, names::render_fieldname(n), ": ", render_field_type(ctxt, !is_struct, d)]
)).collect())],
TSimple::Field(TField::Unit) => semi,
TSimple::Field(t) => seq![parens![seq![ppub, render_field_type(ctxt, !is_struct, t)]], semi],
}]
impl TSimple {
pub fn render(&self, ctxt: &ModuleContext, ptr: Item, is_struct: bool, n: &str) -> impl Emittable {
let semi = if is_struct { seq![";"] } else { seq![] };
let ppub = if is_struct { "pub " } else { "" };
seq![names::render_constructor(n), ptr.to_owned(),
match self {
TSimple::Record(TRecord(fs)) => seq![" ", vertical(false, braces(
fs.iter().map(|(n, d)| item(
seq![ppub, names::render_fieldname(n), ": ", d.render(ctxt, !is_struct)]
)).collect()))],
TSimple::Field(TField::Unit) => semi,
TSimple::Field(t) => seq![parens![seq![ppub, t.render(ctxt, !is_struct)]], semi],
}]
}
pub fn has_embedded(&self, ctxt: &ModuleContext, 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)),
}
}
}
pub fn render_definition_type(
ctxt: &ModuleContext,
n: &str,
t: &TDefinition,
) -> impl Emittable {
seq!["#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Hash)]\n",
match t {
TDefinition::Union(items) =>
seq!["pub enum ", names::render_constructor(n), " ", braces(
items.iter().map(|(n, d)| item(render_recordlike_type(ctxt, false, n, d))).collect())],
TDefinition::Simple(s) =>
seq!["pub struct ", render_recordlike_type(ctxt, true, n, s)],
}]
impl TDefinition {
pub fn generic_decl(&self, ctxt: &ModuleContext) -> Item {
if self.has_embedded(ctxt) {
ctxt.literals_generic_decls()
} else {
item("")
}
}
pub fn generic_decl_with_defaults(&self, ctxt: &ModuleContext) -> Item {
if self.has_embedded(ctxt) {
ctxt.literals_generic_decls_with_defaults()
} else {
item("")
}
}
pub fn generic_arg(&self, ctxt: &ModuleContext) -> Item {
if self.has_embedded(ctxt) {
ctxt.literals_generic_arg()
} else {
item("")
}
}
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) =>
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) =>
seq!["pub struct ", s.render(ctxt, self.generic_decl_with_defaults(ctxt), true, n)],
}])
}
pub fn has_embedded(&self, ctxt: &ModuleContext) -> 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),
}
}
}

View File

@ -14,8 +14,8 @@ use super::types::*;
pub struct UnparserPlugin;
impl compiler::Plugin for UnparserPlugin {
fn generate(&self, module_ctxt: &mut ModuleContext, definition_name: &str, definition: &Definition) {
if module_ctxt.mode.is_some() {
fn generate_definition(&self, module_ctxt: &mut ModuleContext, definition_name: &str, definition: &Definition) {
if let ModuleContextMode::TargetGeneric = module_ctxt.mode {
gen_definition_unparser(module_ctxt, definition_name, definition)
}
}
@ -61,6 +61,8 @@ 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);
m.define_function(
n,
|mut ctxt| {
@ -70,7 +72,7 @@ pub fn gen_definition_unparser(m: &mut ModuleContext, n: &str, d: &Definition) {
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 value ", block(ps.iter().map(
body.push(item(seq!["match self ", block(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));
@ -81,7 +83,7 @@ pub fn gen_definition_unparser(m: &mut ModuleContext, n: &str, d: &Definition) {
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, " = value;"]));
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()
@ -90,16 +92,37 @@ pub fn gen_definition_unparser(m: &mut ModuleContext, n: &str, d: &Definition) {
}
Definition::Pattern(p) => {
let (patpat, vc) = destruct(&mut ctxt, item(names::render_constructor(n)), true, &pattern_type(p));
body.push(item(seq!["let ", patpat, " = value;"]));
body.push(item(seq!["let ", patpat, " = self;"]));
body.push(pattern_unparser(&mut ctxt, p, &vc));
}
}
item(seq!["impl std::convert::From", anglebrackets![seq!["&", names::render_constructor(n)]],
" for ", ctxt.m.target(), " ", block![
seq!["fn from(value: &", names::render_constructor(n), ") -> Self ",
block(body)]]])
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)]]])
});
// m.define_function(
// n,
// |ctxt| {
// let ty_arg = item(seq![names::render_constructor(n), ty.generic_arg(ctxt.m)]);
// item(seq!["impl", ctxt.m.literals_generic_decls(),
// " std::convert::From", anglebrackets![seq!["&", ty_arg.clone()]],
// " for ", ctxt.m.any_type(), " ", block![
// seq!["fn from(value: &", ty_arg, ") -> Self ",
// codeblock![
// seq!["Self::unparse(",
// ctxt.m.literals_base_type(), "::default()",
// ", value)"]]]]])
// });
}
fn destruct(
@ -134,14 +157,8 @@ fn simple_pattern_unparser(
) -> Item {
let src = &vc.src;
match p {
SimplePattern::Any => {
match ctxt.m.mode() {
ModuleContextMode::TargetIOValue =>
item(seq!["_support::encode_embedded", parens![src.as_ref().unwrap().to_owned()]]),
ModuleContextMode::TargetAny =>
item(seq![src.as_ref().unwrap().to_owned(), ".clone()"]),
}
}
SimplePattern::Any =>
item(seq![src.as_ref().unwrap().to_owned(), ".clone()"]),
SimplePattern::Atom { atom_kind: k } => {
match &**k {
AtomKind::Symbol =>
@ -152,14 +169,8 @@ fn simple_pattern_unparser(
item(seq!["preserves::value::Value::from(", src.as_ref().unwrap().to_owned(), ").wrap()"])
}
}
SimplePattern::Embedded { .. } => {
match ctxt.m.mode() {
ModuleContextMode::TargetIOValue =>
item(seq!["preserves::value::Value::Embedded(preserves::value::IOValue::from(&**", src.as_ref().unwrap().to_owned(), ")).wrap()"]),
ModuleContextMode::TargetAny =>
item(seq!["preserves::value::Value::Embedded(", src.as_ref().unwrap().to_owned(), ".clone()).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()"]),
SimplePattern::Seqof { pattern } => {
@ -192,9 +203,9 @@ fn simple_pattern_unparser(
").collect()).wrap()"])
}
SimplePattern::Ref(_r) =>
item(seq![ctxt.m.target(), "::from(", src.as_ref().unwrap().to_owned(),
item(seq![src.as_ref().unwrap().to_owned(),
if vc.is_struct { "" } else { ".as_ref()" },
")"]),
".unparse(_ctxt)"]),
}
}

View File

@ -1 +1,73 @@
pub mod schema;
pub mod schema;
use crate::support as _support;
use _support::preserves;
#[allow(non_snake_case)]
pub struct Literals<N: preserves::value::NestedValue> {
pub LIT_15_FALSE: N /* #f */,
pub LIT_28_1: N /* 1 */,
pub LIT_0_BOOLEAN: N /* Boolean */,
pub LIT_5_BYTE_STRING: N /* ByteString */,
pub LIT_2_DOUBLE: N /* Double */,
pub LIT_1_FLOAT: N /* Float */,
pub LIT_3_SIGNED_INTEGER: N /* SignedInteger */,
pub LIT_4_STRING: N /* String */,
pub LIT_6_SYMBOL: N /* Symbol */,
pub LIT_14_AND: N /* and */,
pub LIT_21_ANY: N /* any */,
pub LIT_22_ATOM: N /* atom */,
pub LIT_8_BUNDLE: N /* bundle */,
pub LIT_18_DEFINITIONS: N /* definitions */,
pub LIT_12_DICT: N /* dict */,
pub LIT_27_DICTOF: N /* dictof */,
pub LIT_23_EMBEDDED: N /* embedded */,
pub LIT_19_EMBEDDED_TYPE: N /* embeddedType */,
pub LIT_24_LIT: N /* lit */,
pub LIT_7_NAMED: N /* named */,
pub LIT_13_OR: N /* or */,
pub LIT_9_REC: N /* rec */,
pub LIT_16_REF: N /* ref */,
pub LIT_17_SCHEMA: N /* schema */,
pub LIT_25_SEQOF: N /* seqof */,
pub LIT_26_SETOF: N /* setof */,
pub LIT_10_TUPLE: N /* tuple */,
pub LIT_11_TUPLE_PREFIX: N /* tuplePrefix */,
pub LIT_20_VERSION: N /* version */
}
impl<N: preserves::value::NestedValue> Default for Literals<N> {
fn default() -> Self {
Literals {
LIT_15_FALSE: /* #f */ _support::decode_lit(&vec![128]).unwrap(),
LIT_28_1: /* 1 */ _support::decode_lit(&vec![145]).unwrap(),
LIT_0_BOOLEAN: /* Boolean */ _support::decode_lit(&vec![179, 7, 66, 111, 111, 108, 101, 97, 110]).unwrap(),
LIT_5_BYTE_STRING: /* ByteString */ _support::decode_lit(&vec![179, 10, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103]).unwrap(),
LIT_2_DOUBLE: /* Double */ _support::decode_lit(&vec![179, 6, 68, 111, 117, 98, 108, 101]).unwrap(),
LIT_1_FLOAT: /* Float */ _support::decode_lit(&vec![179, 5, 70, 108, 111, 97, 116]).unwrap(),
LIT_3_SIGNED_INTEGER: /* SignedInteger */ _support::decode_lit(&vec![179, 13, 83, 105, 103, 110, 101, 100, 73, 110, 116, 101, 103, 101, 114]).unwrap(),
LIT_4_STRING: /* String */ _support::decode_lit(&vec![179, 6, 83, 116, 114, 105, 110, 103]).unwrap(),
LIT_6_SYMBOL: /* Symbol */ _support::decode_lit(&vec![179, 6, 83, 121, 109, 98, 111, 108]).unwrap(),
LIT_14_AND: /* and */ _support::decode_lit(&vec![179, 3, 97, 110, 100]).unwrap(),
LIT_21_ANY: /* any */ _support::decode_lit(&vec![179, 3, 97, 110, 121]).unwrap(),
LIT_22_ATOM: /* atom */ _support::decode_lit(&vec![179, 4, 97, 116, 111, 109]).unwrap(),
LIT_8_BUNDLE: /* bundle */ _support::decode_lit(&vec![179, 6, 98, 117, 110, 100, 108, 101]).unwrap(),
LIT_18_DEFINITIONS: /* definitions */ _support::decode_lit(&vec![179, 11, 100, 101, 102, 105, 110, 105, 116, 105, 111, 110, 115]).unwrap(),
LIT_12_DICT: /* dict */ _support::decode_lit(&vec![179, 4, 100, 105, 99, 116]).unwrap(),
LIT_27_DICTOF: /* dictof */ _support::decode_lit(&vec![179, 6, 100, 105, 99, 116, 111, 102]).unwrap(),
LIT_23_EMBEDDED: /* embedded */ _support::decode_lit(&vec![179, 8, 101, 109, 98, 101, 100, 100, 101, 100]).unwrap(),
LIT_19_EMBEDDED_TYPE: /* embeddedType */ _support::decode_lit(&vec![179, 12, 101, 109, 98, 101, 100, 100, 101, 100, 84, 121, 112, 101]).unwrap(),
LIT_24_LIT: /* lit */ _support::decode_lit(&vec![179, 3, 108, 105, 116]).unwrap(),
LIT_7_NAMED: /* named */ _support::decode_lit(&vec![179, 5, 110, 97, 109, 101, 100]).unwrap(),
LIT_13_OR: /* or */ _support::decode_lit(&vec![179, 2, 111, 114]).unwrap(),
LIT_9_REC: /* rec */ _support::decode_lit(&vec![179, 3, 114, 101, 99]).unwrap(),
LIT_16_REF: /* ref */ _support::decode_lit(&vec![179, 3, 114, 101, 102]).unwrap(),
LIT_17_SCHEMA: /* schema */ _support::decode_lit(&vec![179, 6, 115, 99, 104, 101, 109, 97]).unwrap(),
LIT_25_SEQOF: /* seqof */ _support::decode_lit(&vec![179, 5, 115, 101, 113, 111, 102]).unwrap(),
LIT_26_SETOF: /* setof */ _support::decode_lit(&vec![179, 5, 115, 101, 116, 111, 102]).unwrap(),
LIT_10_TUPLE: /* tuple */ _support::decode_lit(&vec![179, 5, 116, 117, 112, 108, 101]).unwrap(),
LIT_11_TUPLE_PREFIX: /* tuplePrefix */ _support::decode_lit(&vec![179, 11, 116, 117, 112, 108, 101, 80, 114, 101, 102, 105, 120]).unwrap(),
LIT_20_VERSION: /* version */ _support::decode_lit(&vec![179, 7, 118, 101, 114, 115, 105, 111, 110]).unwrap()
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -31,17 +31,16 @@ mod tests {
#[test]
fn metaschema_parsing() -> Result<(), std::io::Error> {
use preserves::value::{BinarySource, IOBinarySource, IOValue, Reader};
use std::convert::TryFrom;
use std::convert::From;
use preserves::value::{BinarySource, IOBinarySource, Reader};
use crate::gen::schema::*;
let mut f = std::fs::File::open("../../../schema/schema.bin")?;
let mut src = IOBinarySource::new(&mut f);
let mut reader = src.packed_iovalues();
let schema = reader.demand_next(false)?;
let parsed = Schema::try_from(&schema).expect("successful parse");
assert_eq!(schema, IOValue::from(&parsed));
let literals = crate::gen::Literals::default();
let parsed = Schema::parse(&literals, &schema).expect("successful parse");
assert_eq!(schema, parsed.unparse(&literals));
Ok(())
}
}

View File

@ -14,10 +14,25 @@ use preserves::value::Value;
use std::convert::From;
use std::convert::TryFrom;
use std::io;
use std::marker::PhantomData;
use std::sync::Arc;
use thiserror::Error;
pub struct Codec<N: NestedValue, L: Default> {
pub literals: L,
phantom: PhantomData<N>,
}
impl<N: NestedValue, L: Default> Codec<N, L> {
pub fn new() -> Self {
Codec {
literals: L::default(),
phantom: PhantomData,
}
}
}
pub trait Deserialize<'de, N: NestedValue, R: Reader<'de, N>>
where
Self: Sized

View File

@ -7,11 +7,24 @@ pub trait Emittable: std::fmt::Debug {
fn write_on(&self, f: &mut Formatter);
}
#[derive(Clone, PartialEq, Eq)]
pub enum VerticalMode {
Variable,
Normal,
ExtraNewline,
}
pub trait Vertical {
fn set_vertical_mode(&mut self, mode: VerticalMode);
fn write_vertically_on(&self, f: &mut Formatter);
}
pub type Item = std::rc::Rc<dyn Emittable>;
#[derive(Clone)]
pub struct Sequence {
pub items: Vec<Item>,
pub vertical_mode: VerticalMode,
pub separator: &'static str,
pub terminator: &'static str,
}
@ -80,6 +93,12 @@ impl Formatter {
}
}
impl Default for VerticalMode {
fn default() -> Self {
Self::Variable
}
}
//---------------------------------------------------------------------------
impl Emittable for &str {
@ -104,48 +123,86 @@ impl<'a, E: Emittable> Emittable for &'a Vec<E> where &'a E: Emittable {
impl Emittable for Sequence {
fn write_on(&self, f: &mut Formatter) {
let mut need_sep = false;
for e in self.items.iter() {
if need_sep {
self.separator.write_on(f)
} else {
need_sep = true
if self.vertical_mode != VerticalMode::Variable {
self.write_vertically_on(f)
} else {
let mut need_sep = false;
for e in self.items.iter() {
if need_sep {
self.separator.write_on(f)
} else {
need_sep = true
}
e.write_on(f)
}
if !self.items.is_empty() {
self.terminator.write_on(f)
}
e.write_on(f)
}
self.terminator.write_on(f)
}
}
impl Vertical for Sequence {
fn set_vertical_mode(&mut self, vertical_mode: VerticalMode) {
self.vertical_mode = vertical_mode;
}
fn write_vertically_on(&self, f: &mut Formatter) {
let mut i = self.items.len();
let mut first = true;
for e in self.items.iter() {
if !first {
if self.vertical_mode == VerticalMode::ExtraNewline {
f.write("\n");
}
f.newline();
}
first = false;
e.write_on(f);
let delim = if i == 1 { self.terminator } else { self.separator };
delim.trim_end_matches(|c: char| c.is_whitespace() && c != '\n').write_on(f);
i = i - 1;
}
}
}
impl Emittable for Grouping {
fn write_on(&self, f: &mut Formatter) {
let mut g = f.copy_empty();
self.open.write_on(&mut g);
g.write(&self.sequence);
self.close.write_on(&mut g);
let s = g.buffer;
if s.len() <= f.width {
f.write(&s)
if self.sequence.vertical_mode != VerticalMode::Variable {
self.write_vertically_on(f)
} else {
self.open.write_on(f);
if !self.sequence.items.is_empty() {
f.with_indent(|f| {
let mut i = self.sequence.items.len();
for e in self.sequence.items.iter() {
f.newline();
e.write_on(f);
let delim = if i == 1 { self.sequence.terminator } else { self.sequence.separator };
delim.trim_end().write_on(f);
i = i - 1;
}
});
f.newline()
let mut g = f.copy_empty();
self.open.write_on(&mut g);
g.write(&self.sequence);
self.close.write_on(&mut g);
let s = g.buffer;
if s.len() <= f.width {
f.write(&s)
} else {
self.write_vertically_on(f)
}
self.close.write_on(f);
}
}
}
impl Vertical for Grouping {
fn set_vertical_mode(&mut self, vertical_mode: VerticalMode) {
self.sequence.set_vertical_mode(vertical_mode);
}
fn write_vertically_on(&self, f: &mut Formatter) {
self.open.write_on(f);
if !self.sequence.items.is_empty() {
f.with_indent(|f| {
f.newline();
self.sequence.write_vertically_on(f)
});
f.newline()
}
self.close.write_on(f);
}
}
impl<'a, E: Emittable> Emittable for &'a E {
fn write_on(&self, f: &mut Formatter) {
(*self).write_on(f)
@ -210,21 +267,23 @@ pub mod constructors {
use super::Grouping;
use super::Item;
use super::Emittable;
use super::VerticalMode;
use super::Vertical;
pub fn item<E: 'static + Emittable>(i: E) -> Item {
std::rc::Rc::new(i)
}
pub fn name(pieces: Vec<Item>) -> Sequence {
Sequence { items: pieces, separator: "::", terminator: "" }
Sequence { items: pieces, vertical_mode: VerticalMode::default(), separator: "::", terminator: "" }
}
pub fn seq(items: Vec<Item>) -> Sequence {
Sequence { items: items, separator: "", terminator: "" }
Sequence { items: items, vertical_mode: VerticalMode::default(), separator: "", terminator: "" }
}
pub fn commas(items: Vec<Item>) -> Sequence {
Sequence { items: items, separator: ", ", terminator: "" }
Sequence { items: items, vertical_mode: VerticalMode::default(), separator: ", ", terminator: "" }
}
pub fn parens(items: Vec<Item>) -> Grouping {
@ -245,19 +304,38 @@ pub mod constructors {
pub fn block(items: Vec<Item>) -> Grouping {
Grouping {
sequence: Sequence { items: items, separator: " ", terminator: "" },
sequence: Sequence {
items: items,
vertical_mode: VerticalMode::default(),
separator: " ",
terminator: "",
},
open: "{",
close: "}",
}
}
pub fn codeblock(items: Vec<Item>) -> Grouping {
vertical(false, block(items))
}
pub fn semiblock(items: Vec<Item>) -> Grouping {
Grouping {
sequence: Sequence { items: items, separator: "; ", terminator: "" },
sequence: Sequence {
items: items,
vertical_mode: VerticalMode::default(),
separator: "; ",
terminator: "",
},
open: "{",
close: "}",
}
}
pub fn vertical<V: Vertical>(spaced: bool, mut v: V) -> V {
v.set_vertical_mode(if spaced { VerticalMode::ExtraNewline } else { VerticalMode::Normal });
v
}
}
pub mod macros {
@ -301,6 +379,11 @@ pub mod macros {
($($item:expr),*) => {crate::syntax::block::constructors::block(vec![$(std::rc::Rc::new($item)),*])}
}
#[macro_export]
macro_rules! codeblock {
($($item:expr),*) => {crate::syntax::block::constructors::codeblock(vec![$(std::rc::Rc::new($item)),*])}
}
#[macro_export]
macro_rules! semiblock {
($($item:expr),*) => {crate::syntax::block::constructors::semiblock(vec![$(std::rc::Rc::new($item)),*])}