From 94e9fabc70ccf929984a0ea5702b3a69f65cdd79 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Mon, 20 Sep 2021 14:32:24 +0200 Subject: [PATCH] Make WalkState reusable; add lookup_definition --- .../preserves-schema/src/compiler/context.rs | 4 ++ .../preserves-schema/src/compiler/cycles.rs | 46 ++++++++++++ .../rust/preserves-schema/src/compiler/mod.rs | 1 + .../preserves-schema/src/compiler/types.rs | 71 ++++++------------- 4 files changed, 72 insertions(+), 50 deletions(-) create mode 100644 implementations/rust/preserves-schema/src/compiler/cycles.rs diff --git a/implementations/rust/preserves-schema/src/compiler/context.rs b/implementations/rust/preserves-schema/src/compiler/context.rs index c4c191b..f54c277 100644 --- a/implementations/rust/preserves-schema/src/compiler/context.rs +++ b/implementations/rust/preserves-schema/src/compiler/context.rs @@ -82,6 +82,10 @@ 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 type_for_name(&self, r: &Ref) -> Option<&types::TDefinition> { if r.module.0.is_empty() { panic!("BundleContext::type_for_name with module-relative ref {:?}", r); diff --git a/implementations/rust/preserves-schema/src/compiler/cycles.rs b/implementations/rust/preserves-schema/src/compiler/cycles.rs new file mode 100644 index 0000000..f3b0873 --- /dev/null +++ b/implementations/rust/preserves-schema/src/compiler/cycles.rs @@ -0,0 +1,46 @@ +use preserves::value::Set; + +use crate::gen::schema::ModulePath; +use crate::gen::schema::Ref; + +pub struct WalkState { + pub context: T, + pub module_path: ModulePath, + seen: Set, +} + +impl WalkState { + pub fn new(context: T, module_path: ModulePath) -> Self { + WalkState { + context, + module_path, + seen: Set::new(), + } + } + + pub fn cycle_check< + E, + F: Fn(&T, &Ref) -> Option, + R, + Ks: FnOnce(&mut Self, Option) -> R, + Kf: FnOnce() -> R + >( + &mut self, + r: &Ref, + step: F, + ks: Ks, + kf: Kf, + ) -> R { + let r = r.qualify(&self.module_path); + if self.seen.contains(&r) { + kf() + } else { + self.seen.insert(r.clone()); + let maybe_e = step(&self.context, &r); + let saved = std::mem::replace(&mut self.module_path, r.module); + let result = ks(self, maybe_e); + self.module_path = saved; + result + } + } +} diff --git a/implementations/rust/preserves-schema/src/compiler/mod.rs b/implementations/rust/preserves-schema/src/compiler/mod.rs index 27ad08f..ebb8c64 100644 --- a/implementations/rust/preserves-schema/src/compiler/mod.rs +++ b/implementations/rust/preserves-schema/src/compiler/mod.rs @@ -1,4 +1,5 @@ pub mod context; +pub mod cycles; pub mod names; pub mod parsers; pub mod readers; diff --git a/implementations/rust/preserves-schema/src/compiler/types.rs b/implementations/rust/preserves-schema/src/compiler/types.rs index 63d30df..2c659c2 100644 --- a/implementations/rust/preserves-schema/src/compiler/types.rs +++ b/implementations/rust/preserves-schema/src/compiler/types.rs @@ -191,36 +191,7 @@ pub fn field_type(p: &SimplePattern) -> TField { } } -struct WalkState<'a, 'b> { - ctxt: &'a BundleContext<'b>, - current_module_path: ModulePath, - seen: Set, -} - -impl<'a, 'b> WalkState<'a, 'b> { - fn cycle_check) -> R, Kf: FnOnce() -> R>( - &mut self, - r: &Ref, - ks: Ks, - kf: Kf, - ) -> R { - let r = r.qualify(&self.current_module_path); - if self.seen.contains(&r) { - kf() - } else { - self.seen.insert(r.clone()); - match self.ctxt.type_for_name(&r) { - Some(ty) => { - let saved = std::mem::replace(&mut self.current_module_path, ty.self_ref.module.clone()); - let result = ks(self, Some(ty)); - self.current_module_path = saved; - result - }, - None => ks(self, None), - } - } - } -} +type WalkState<'a, 'b> = super::cycles::WalkState<&'a BundleContext<'b>>; impl TField { fn render(&self, ctxt: &ModuleContext, box_needed: bool) -> impl Emittable { @@ -254,16 +225,20 @@ impl TField { v.language_types(s, ts); } TField::Ref(r) => - s.cycle_check(r, |s,t| match t { - Some(ty) => ty._language_types(s, ts), - None => { - let xmts = &s.ctxt.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()) { - ts.extend(f(s.ctxt.any_type())); + s.cycle_check( + r, + |ctxt, r| ctxt.type_for_name(r), + |s, t| match t { + Some(ty) => ty._language_types(s, ts), + 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()) { + ts.extend(f(s.context.any_type())); + } } - } - }, || ()), + }, + || ()), } } @@ -276,7 +251,11 @@ impl TField { TField::Map(k, v) => k.has_embedded(s) || v.has_embedded(s), TField::Ref(r) => // v TODO: should the "false" be configurable? cf. ModuleContext::ref_has_embedded. - s.cycle_check(r, |s,t| t.map(|t| t._has_embedded(s)).unwrap_or(false), || false), + s.cycle_check( + r, + |ctxt, r| ctxt.type_for_name(r), + |s, t| t.map(|t| t._has_embedded(s)).unwrap_or(false), + || false), } } } @@ -357,11 +336,7 @@ impl TDefinition { } fn walk_state<'a, 'b>(&self, ctxt: &'a BundleContext<'b>) -> WalkState<'a, 'b> { - WalkState { - current_module_path: self.self_ref.module.clone(), - ctxt, - seen: Set::new(), - } + WalkState::new(ctxt, self.self_ref.module.clone()) } pub fn language_types(&self, ctxt: &BundleContext) -> Set { @@ -378,11 +353,7 @@ impl TDefinition { } pub fn has_embedded(&self, ctxt: &BundleContext) -> bool { - self._has_embedded(&mut WalkState { - current_module_path: self.self_ref.module.clone(), - ctxt, - seen: Set::new(), - }) + self._has_embedded(&mut self.walk_state(ctxt)) } fn _has_embedded(&self, s: &mut WalkState) -> bool {