use super::{smallvec, CompactString, Scope, ScopeBinding, ScopeChain, ScopeId, SmallVec};
impl ScopeChain {
#[inline]
pub fn lookup(&self, name: &str) -> Option<(&Scope, &ScopeBinding)> {
let mut visited: SmallVec<[ScopeId; 8]> = SmallVec::new();
let mut queue: SmallVec<[ScopeId; 8]> = smallvec![self.current];
while let Some(id) = queue.pop() {
if visited.contains(&id) {
continue;
}
visited.push(id);
let scope = unsafe { self.scopes.get_unchecked(id.as_u32() as usize) };
if let Some(binding) = scope.get_binding(name) {
return Some((scope, binding));
}
for &parent_id in &scope.parents {
if !visited.contains(&parent_id) {
queue.push(parent_id);
}
}
}
None
}
#[inline]
pub fn is_defined(&self, name: &str) -> bool {
self.lookup(name).is_some()
}
#[inline]
pub fn add_binding(&mut self, name: CompactString, binding: ScopeBinding) {
self.current_scope_mut().add_binding(name, binding);
}
pub fn mark_used(&mut self, name: &str) {
let mut visited: SmallVec<[ScopeId; 8]> = SmallVec::new();
let mut queue: SmallVec<[ScopeId; 8]> = smallvec![self.current];
while let Some(id) = queue.pop() {
if visited.contains(&id) {
continue;
}
visited.push(id);
let scope = &mut self.scopes[id.as_u32() as usize];
if let Some(binding) = scope.get_binding_mut(name) {
binding.mark_used();
return;
}
let parents: SmallVec<[ScopeId; 2]> = scope.parents.clone();
for parent_id in parents {
if !visited.contains(&parent_id) {
queue.push(parent_id);
}
}
}
}
pub fn is_used(&self, name: &str) -> bool {
for scope in &self.scopes {
if let Some(binding) = scope.get_binding(name) {
return binding.is_used();
}
}
false
}
pub fn mark_mutated(&mut self, name: &str) {
let mut visited: SmallVec<[ScopeId; 8]> = SmallVec::new();
let mut queue: SmallVec<[ScopeId; 8]> = smallvec![self.current];
while let Some(id) = queue.pop() {
if visited.contains(&id) {
continue;
}
visited.push(id);
let scope = &mut self.scopes[id.as_u32() as usize];
if let Some(binding) = scope.get_binding_mut(name) {
binding.mark_mutated();
return;
}
let parents: SmallVec<[ScopeId; 2]> = scope.parents.clone();
for parent_id in parents {
if !visited.contains(&parent_id) {
queue.push(parent_id);
}
}
}
}
#[inline]
pub fn depth(&self, id: ScopeId) -> u32 {
let mut depth = 0u32;
let mut current_id = self.get_scope(id).and_then(|s| s.parent());
while let Some(pid) = current_id {
depth += 1;
current_id = self.get_scope(pid).and_then(|s| s.parent());
}
depth
}
}