Make WalkState reusable; add lookup_definition

This commit is contained in:
Tony Garnock-Jones 2021-09-20 14:32:24 +02:00
parent f778325748
commit 94e9fabc70
4 changed files with 72 additions and 50 deletions

View File

@ -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);

View File

@ -0,0 +1,46 @@
use preserves::value::Set;
use crate::gen::schema::ModulePath;
use crate::gen::schema::Ref;
pub struct WalkState<T> {
pub context: T,
pub module_path: ModulePath,
seen: Set<Ref>,
}
impl<T> WalkState<T> {
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<E>,
R,
Ks: FnOnce(&mut Self, Option<E>) -> 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
}
}
}

View File

@ -1,4 +1,5 @@
pub mod context;
pub mod cycles;
pub mod names;
pub mod parsers;
pub mod readers;

View File

@ -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<Ref>,
}
impl<'a, 'b> WalkState<'a, 'b> {
fn cycle_check<R, Ks: FnOnce(&mut Self, Option<&TDefinition>) -> 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<String> {
@ -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 {