From 7f387d6d711e42a99b9d3d65db74f0d6d9104317 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Sat, 28 Jan 2023 22:38:14 +0100 Subject: [PATCH] Support xrefs in schema compiler; offer Arc for languages --- implementations/rust/preserves-path/build.rs | 2 +- .../src/bin/preserves-schema-rs.rs | 7 ++- .../preserves-schema/src/compiler/context.rs | 12 ++--- .../rust/preserves-schema/src/compiler/mod.rs | 45 ++++++++++++++----- .../preserves-schema/src/compiler/parsers.rs | 2 +- .../preserves-schema/src/compiler/readers.rs | 2 +- .../preserves-schema/src/compiler/types.rs | 16 +++++-- .../src/compiler/unparsers.rs | 10 ++--- .../rust/preserves-schema/src/lib.rs | 13 ++++-- 9 files changed, 78 insertions(+), 31 deletions(-) diff --git a/implementations/rust/preserves-path/build.rs b/implementations/rust/preserves-path/build.rs index 596e862..5e838f6 100644 --- a/implementations/rust/preserves-path/build.rs +++ b/implementations/rust/preserves-path/build.rs @@ -12,7 +12,7 @@ fn main() -> Result<(), Error> { let mut c = CompilerConfig::new(gen_dir, "crate::schemas".to_owned()); let inputs = expand_inputs(&vec!["path.bin".to_owned()])?; - c.load_schemas_and_bundles(&inputs)?; + c.load_schemas_and_bundles(&inputs, &vec![])?; compile(&c) } diff --git a/implementations/rust/preserves-schema/src/bin/preserves-schema-rs.rs b/implementations/rust/preserves-schema/src/bin/preserves-schema-rs.rs index 8d7d9fd..fc4cea5 100644 --- a/implementations/rust/preserves-schema/src/bin/preserves-schema-rs.rs +++ b/implementations/rust/preserves-schema/src/bin/preserves-schema-rs.rs @@ -19,6 +19,9 @@ struct CommandLine { #[structopt(long)] module: Vec, + #[structopt(long)] + xref: Vec, + input_glob: Vec, } @@ -40,6 +43,8 @@ fn main() -> Result<(), Error> { if let Some(c) = args.support_crate { config.support_crate = c; } - config.load_schemas_and_bundles(&expand_inputs(&args.input_glob)?)?; + config.load_schemas_and_bundles( + &expand_inputs(&args.input_glob)?, + &expand_inputs(&args.xref)?)?; compile(&config) } diff --git a/implementations/rust/preserves-schema/src/compiler/context.rs b/implementations/rust/preserves-schema/src/compiler/context.rs index 57859b2..1c98dcc 100644 --- a/implementations/rust/preserves-schema/src/compiler/context.rs +++ b/implementations/rust/preserves-schema/src/compiler/context.rs @@ -16,6 +16,7 @@ use preserves::value::Value; use super::CompilerConfig; use super::names; use super::types; +use super::types::Purpose; pub struct BundleContext<'b> { pub config: &'b CompilerConfig, @@ -82,8 +83,9 @@ impl<'b> BundleContext<'b> { "_Value" } - pub fn lookup_definition(&self, r: &Ref) -> Option<&Definition> { - self.config.bundle.get(&r.module.0).and_then(|s| s.definitions.0.get(&r.name)) + pub fn lookup_definition(&self, r: &Ref) -> Option<(&Definition, Purpose)> { + self.config.bundle.get(&r.module.0).and_then( + |s| s.0.definitions.0.get(&r.name).map(|d| (d, s.1))) } pub fn type_for_name(&self, r: &Ref) -> Option<&types::TDefinition> { @@ -229,7 +231,7 @@ 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, + m, temp_counter: 0, captures: Vec::new(), capture_mode: CaptureMode::Definite, @@ -238,8 +240,8 @@ impl<'a, 'm, 'b> FunctionContext<'a, 'm, 'b> { pub fn capture(&mut self, field_name: String, ty: types::TField, source_expr: String) { self.captures.push(Capture { - field_name: field_name, - ty: ty, + field_name, + ty, source_expr: match self.capture_mode { CaptureMode::Definite => source_expr, diff --git a/implementations/rust/preserves-schema/src/compiler/mod.rs b/implementations/rust/preserves-schema/src/compiler/mod.rs index 1fda19e..2cc9c3e 100644 --- a/implementations/rust/preserves-schema/src/compiler/mod.rs +++ b/implementations/rust/preserves-schema/src/compiler/mod.rs @@ -8,6 +8,7 @@ pub mod unparsers; use crate::*; use crate::compiler::context::*; +use crate::compiler::types::Purpose; use crate::gen::Language; use crate::gen::schema; use crate::gen::schema::*; @@ -97,7 +98,7 @@ impl ExternalModule { #[derive(Debug)] pub struct CompilerConfig { - pub bundle: Map, + pub bundle: Map, pub output_dir: PathBuf, pub fully_qualified_module_prefix: String, pub support_crate: String, @@ -105,7 +106,21 @@ pub struct CompilerConfig { pub plugins: Vec>, } -pub fn load_schema_or_bundle(bundle: &mut Map, i: &PathBuf) -> io::Result<()> { +pub fn load_schema_or_bundle_with_purpose( + bundle: &mut Map, + i: &PathBuf, + purpose: Purpose, +) -> io::Result<()> { + let mut inserted = Map::::new(); + load_schema_or_bundle(&mut inserted, i)?; + for (k, v) in inserted.into_iter() { bundle.insert(k, (v, purpose)); } + Ok(()) +} + +pub fn load_schema_or_bundle( + bundle: &mut Map, + i: &PathBuf, +) -> io::Result<()> { let mut f = File::open(&i)?; let mut src = IOBinarySource::new(&mut f); let mut reader = src.packed_iovalues(); @@ -139,8 +154,8 @@ impl CompilerConfig { ) -> Self { CompilerConfig { bundle: Map::new(), - output_dir: output_dir, - fully_qualified_module_prefix: fully_qualified_module_prefix, + output_dir, + fully_qualified_module_prefix, support_crate: "preserves_schema".to_owned(), external_modules: Map::new(), plugins: vec![ @@ -159,9 +174,12 @@ impl CompilerConfig { } } - pub fn load_schemas_and_bundles(&mut self, inputs: &Vec) -> io::Result<()> { + pub fn load_schemas_and_bundles(&mut self, inputs: &Vec, xrefs: &Vec) -> io::Result<()> { for i in inputs { - load_schema_or_bundle(&mut self.bundle, i)?; + load_schema_or_bundle_with_purpose(&mut self.bundle, i, Purpose::Codegen)?; + } + for i in xrefs { + load_schema_or_bundle_with_purpose(&mut self.bundle, i, Purpose::Xref)?; } Ok(()) } @@ -169,8 +187,8 @@ impl CompilerConfig { fn build_type_cache(&self) -> Map { 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); + s.0.definitions.0.iter().map(move |(name, def)| { + let ty = types::definition_type(&modpath, s.1, name, def); (ty.self_ref.clone(), ty) }) }).collect() @@ -237,7 +255,11 @@ impl Schema { pub fn compile(config: &CompilerConfig) -> io::Result<()> { let mut b = BundleContext::new(config); - for (k, v) in config.bundle.iter() { + for (k, (v, module_purpose)) in config.bundle.iter() { + if *module_purpose != Purpose::Codegen { + continue; + } + let mut output_path = config.output_dir.clone(); output_path.extend(k); let module_name = output_path.file_stem().unwrap().to_str().unwrap().to_owned(); @@ -300,7 +322,10 @@ pub fn compile(config: &CompilerConfig) -> io::Result<()> { mod_rs.extend(vec!["mod.rs"]); let mut lines = Vec::new(); - for modpath in config.bundle.keys() { + for (modpath, (_, module_purpose)) in config.bundle.iter() { + if *module_purpose != Purpose::Codegen { + continue; + } lines.push(format!("pub mod {};", names::render_modname(modpath.last().unwrap()))); } lines.push("".to_owned()); diff --git a/implementations/rust/preserves-schema/src/compiler/parsers.rs b/implementations/rust/preserves-schema/src/compiler/parsers.rs index 5c9419d..f31e6a8 100644 --- a/implementations/rust/preserves-schema/src/compiler/parsers.rs +++ b/implementations/rust/preserves-schema/src/compiler/parsers.rs @@ -22,7 +22,7 @@ impl compiler::Plugin for ParserPlugin { } pub fn gen_definition_parser(m: &mut ModuleContext, n: &str, d: &Definition) { - let ty = definition_type(&m.module_path, n, d); + let ty = definition_type(&m.module_path, Purpose::Codegen, n, d); m.define_function( n, diff --git a/implementations/rust/preserves-schema/src/compiler/readers.rs b/implementations/rust/preserves-schema/src/compiler/readers.rs index 9a9cea6..d2aff99 100644 --- a/implementations/rust/preserves-schema/src/compiler/readers.rs +++ b/implementations/rust/preserves-schema/src/compiler/readers.rs @@ -78,7 +78,7 @@ impl BoundaryTracker { } pub fn gen_definition_reader(m: &mut ModuleContext, n: &str, d: &Definition) { - let ty = definition_type(&m.module_path, n, d); + let ty = definition_type(&m.module_path, Purpose::Codegen, n, d); m.define_function( n, diff --git a/implementations/rust/preserves-schema/src/compiler/types.rs b/implementations/rust/preserves-schema/src/compiler/types.rs index 2c659c2..2a452ab 100644 --- a/implementations/rust/preserves-schema/src/compiler/types.rs +++ b/implementations/rust/preserves-schema/src/compiler/types.rs @@ -11,8 +11,15 @@ use super::context::ModuleContextMode; use super::context::RefRenderStyle; use super::names; +#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)] +pub enum Purpose { + Codegen, + Xref, +} + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] pub struct TDefinition { + pub purpose: Purpose, pub self_ref: Ref, pub body: TDefinitionBody, } @@ -60,7 +67,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(&m.module_path, n, d); + let ty = definition_type(&m.module_path, Purpose::Codegen, n, d); m.define_type(item(ty.render(m, n))); m.define_type(item(seq![ "impl", ty.generic_decl(m), " preserves::value::Domain for ", @@ -69,8 +76,9 @@ impl compiler::Plugin for TypePlugin { } } -pub fn definition_type(module: &ModulePath, n: &str, d: &Definition) -> TDefinition { +pub fn definition_type(module: &ModulePath, purpose: Purpose, n: &str, d: &Definition) -> TDefinition { TDefinition { + purpose, self_ref: Ref { module: module.clone(), name: n.to_owned() }, body: match d { Definition::Or { pattern_0, pattern_1, pattern_n } => @@ -229,8 +237,8 @@ impl TField { r, |ctxt, r| ctxt.type_for_name(r), |s, t| match t { - Some(ty) => ty._language_types(s, ts), - None => { + Some(ty) if ty.purpose == Purpose::Codegen => ty._language_types(s, ts), + Some(_) | None => { let xmts = &s.context.config.external_modules.get(&r.module.0).unwrap() .rust_language_types; if let Some(f) = xmts.definitions.get(&r.name).or(xmts.fallback.as_ref()) { diff --git a/implementations/rust/preserves-schema/src/compiler/unparsers.rs b/implementations/rust/preserves-schema/src/compiler/unparsers.rs index eec1cb9..ee27e58 100644 --- a/implementations/rust/preserves-schema/src/compiler/unparsers.rs +++ b/implementations/rust/preserves-schema/src/compiler/unparsers.rs @@ -53,15 +53,15 @@ struct ValueContext { } fn normal_none(is_struct: bool) -> ValueContext { - ValueContext { src: None, sink: ValueSink::Normal, is_struct: is_struct } + ValueContext { src: None, sink: ValueSink::Normal, is_struct } } fn normal_src(src: String, is_struct: bool) -> ValueContext { - ValueContext { src: Some(src), sink: ValueSink::Normal, is_struct: is_struct } + ValueContext { src: Some(src), sink: ValueSink::Normal, is_struct } } pub fn gen_definition_unparser(m: &mut ModuleContext, n: &str, d: &Definition) { - let ty = definition_type(&m.module_path, n, d); + let ty = definition_type(&m.module_path, Purpose::Codegen, n, d); m.define_function( n, @@ -234,7 +234,7 @@ fn pattern_unparser( sink: ValueSink::Fields(Rc::new(Cell::new(Some(FieldsSink { finish: item(seq![rtmp.clone(), ".finish().wrap()"]), vec_expr: item(seq![rtmp.clone(), ".fields_vec_mut()"]), - body: body, + body, })))), is_struct: vc.is_struct, }) @@ -285,7 +285,7 @@ fn sequenceify<'a>( finish: item(seq![ "preserves::value::Value::Sequence", parens![rtmp.clone()], ".wrap()"]), vec_expr: item(rtmp), - body: body, + body, } } } diff --git a/implementations/rust/preserves-schema/src/lib.rs b/implementations/rust/preserves-schema/src/lib.rs index 39be38c..82a7232 100644 --- a/implementations/rust/preserves-schema/src/lib.rs +++ b/implementations/rust/preserves-schema/src/lib.rs @@ -70,9 +70,16 @@ macro_rules! define_language { mod $fname { use super::*; lazy_static::lazy_static! { - pub static ref GLOBAL_LANG: $lang<$default_value> = $lang { - $($field: std::sync::Arc::new($($type)::*::default())),* - }; + pub static ref GLOBAL_LANG: std::sync::Arc<$lang<$default_value>> = + std::sync::Arc::new($lang { + $($field: std::sync::Arc::new($($type)::*::default())),* + }); + } + } + + impl $lang<$default_value> { + pub fn arc() -> &'static std::sync::Arc<$lang<$default_value>> { + &*$fname::GLOBAL_LANG } }