forked from syndicate-lang/preserves
Make WalkState reusable; add lookup_definition
This commit is contained in:
parent
f778325748
commit
94e9fabc70
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
pub mod context;
|
||||
pub mod cycles;
|
||||
pub mod names;
|
||||
pub mod parsers;
|
||||
pub mod readers;
|
||||
|
|
|
@ -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 {
|
||||
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.ctxt.config.external_modules.get(&r.module.0).unwrap()
|
||||
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.ctxt.any_type()));
|
||||
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 {
|
||||
|
|
Loading…
Reference in New Issue