use preserves_schema::compiler::*; mod pattern_plugin { use preserves_schema::*; use preserves_schema::compiler::*; use preserves_schema::compiler::context::ModuleContext; use preserves_schema::gen::schema::*; use preserves_schema::syntax::block::escape_string; use preserves_schema::syntax::block::constructors::*; use std::iter::FromIterator; use syndicate::schemas::dataspace_patterns as P; use syndicate::value::IOValue; use syndicate::value::Map; use syndicate::value::NestedValue; use syndicate::value::signed_integer::SignedInteger; #[derive(Debug)] pub struct PatternPlugin; type WalkState<'a, 'm, 'b> = preserves_schema::compiler::cycles::WalkState<&'a ModuleContext<'m, 'b>>; impl Plugin for PatternPlugin { fn generate_definition( &self, ctxt: &mut ModuleContext, definition_name: &str, definition: &Definition, ) { if ctxt.mode == context::ModuleContextMode::TargetGeneric { let mut s = WalkState::new(ctxt, ctxt.module_path.clone()); if let Some(p) = definition.wc(&mut s) { let v = syndicate::language().unparse(&p); let v = preserves_schema::support::preserves::value::TextWriter::encode( &mut preserves_schema::support::preserves::value::NoEmbeddedDomainCodec, &v).unwrap(); ctxt.define_type(item(seq![ "impl ", definition_name.to_owned(), " ", codeblock![ seq!["#[allow(unused)] pub fn wildcard_dataspace_pattern() ", "-> syndicate::schemas::dataspace_patterns::Pattern ", codeblock![ "use syndicate::schemas::dataspace_patterns::*;", "use preserves_schema::Codec;", seq!["let _v = syndicate::value::text::from_str(", escape_string(&v), ", syndicate::value::ViaCodec::new(syndicate::value::NoEmbeddedDomainCodec)).unwrap();"], "syndicate::language().parse(&_v).unwrap()"]]]])); } } } } fn discard() -> P::Pattern { P::Pattern::DDiscard(Box::new(P::DDiscard)) } trait WildcardPattern { fn wc(&self, s: &mut WalkState) -> Option; } impl WildcardPattern for Definition { fn wc(&self, s: &mut WalkState) -> Option { match self { Definition::Or { .. } => None, Definition::And { .. } => None, Definition::Pattern(p) => p.wc(s), } } } impl WildcardPattern for Pattern { fn wc(&self, s: &mut WalkState) -> Option { match self { Pattern::CompoundPattern(p) => p.wc(s), Pattern::SimplePattern(p) => p.wc(s), } } } fn from_io(v: &IOValue) -> Option { Some(v.value().copy_via(&mut |_| Err(())).ok()?.wrap()) } impl WildcardPattern for CompoundPattern { fn wc(&self, s: &mut WalkState) -> Option { match self { CompoundPattern::Tuple { patterns } => Some(P::Pattern::DCompound(Box::new(P::DCompound::Arr { ctor: Box::new(P::CArr { arity: patterns.len().into() }), members: Map::from_iter( patterns.iter().enumerate() .map(|(i, p)| Some((i.into(), unname(p).wc(s)?))) .filter(|e| discard() != e.as_ref().unwrap().1) .collect::>>()? .into_iter()), }))), CompoundPattern::TuplePrefix { .. } => Some(discard()), CompoundPattern::Dict { entries } => Some(P::Pattern::DCompound(Box::new(P::DCompound::Dict { ctor: Box::new(P::CDict), members: Map::from_iter( entries.0.iter() .map(|(k, p)| Some((from_io(k)?, unname_simple(p).wc(s)?))) .filter(|e| discard() != e.as_ref().unwrap().1) .collect::>>()? .into_iter()), }))), CompoundPattern::Rec { label, fields } => match (unname(label), unname(fields)) { (Pattern::SimplePattern(label), Pattern::CompoundPattern(fields)) => match (*label, *fields) { (SimplePattern::Lit { value }, CompoundPattern::Tuple { patterns }) => Some(P::Pattern::DCompound(Box::new(P::DCompound::Rec { ctor: Box::new(P::CRec { label: from_io(&value)?, arity: patterns.len().into(), }), members: Map::from_iter( patterns.iter().enumerate() .map(|(i, p)| Some((i.into(), unname(p).wc(s)?))) .filter(|e| discard() != e.as_ref().unwrap().1) .collect::>>()? .into_iter()), }))), _ => None, }, _ => None, }, } } } impl WildcardPattern for SimplePattern { fn wc(&self, s: &mut WalkState) -> Option { match self { SimplePattern::Any | SimplePattern::Atom { .. } | SimplePattern::Embedded { .. } | SimplePattern::Seqof { .. } | SimplePattern::Setof { .. } | SimplePattern::Dictof { .. } => Some(discard()), SimplePattern::Lit { value } => Some(P::Pattern::DLit(Box::new(P::DLit { value: from_io(&value)?, }))), SimplePattern::Ref(r) => s.cycle_check( r, |ctxt, r| ctxt.bundle.lookup_definition(r), |s, d| d.and_then(|d| d.wc(s)).or_else(|| Some(discard())), || Some(discard())), } } } fn unname(np: &NamedPattern) -> Pattern { match np { NamedPattern::Anonymous(p) => (**p).clone(), NamedPattern::Named(b) => Pattern::SimplePattern(Box::new(b.pattern.clone())), } } fn unname_simple(np: &NamedSimplePattern) -> &SimplePattern { match np { NamedSimplePattern::Anonymous(p) => p, NamedSimplePattern::Named(b) => &b.pattern, } } } fn main() -> std::io::Result<()> { let buildroot = std::path::PathBuf::from(std::env::var_os("OUT_DIR").unwrap()); let mut gen_dir = buildroot.clone(); gen_dir.push("src/schemas"); let mut c = CompilerConfig::new(gen_dir, "crate::schemas".to_owned()); c.plugins.push(Box::new(pattern_plugin::PatternPlugin)); c.add_external_module(ExternalModule::new(vec!["EntityRef".to_owned()], "syndicate::actor")); c.add_external_module( ExternalModule::new(vec!["TransportAddress".to_owned()], "syndicate::schemas::transport_address") .set_fallback_language_types( |v| vec![format!("syndicate::schemas::Language<{}>", v)].into_iter().collect())); let inputs = expand_inputs(&vec!["protocols/schema-bundle.bin".to_owned()])?; c.load_schemas_and_bundles(&inputs)?; compile(&c) }