use super::bindings::BindingId;
use crate::engine::compiler::model::bindings::IrBinding;
use crate::engine::compiler::names::NameId;
use oxide_core::FxHashMap;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub(in crate::engine::compiler) struct ScopeId(pub(in crate::engine::compiler) u32);
impl ScopeId {
pub(in crate::engine::compiler) const fn new(index: usize) -> Self {
Self(index as u32)
}
pub(in crate::engine::compiler) const fn index(self) -> usize {
self.0 as usize
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(in crate::engine::compiler) enum ScopeKind {
FunctionRoot,
Parameter,
FunctionBody,
ProgramBody,
Block,
ClassPrivate,
If,
For,
Switch,
Catch,
With,
}
#[derive(Debug)]
pub(in crate::engine::compiler) struct IrScope {
pub(in crate::engine::compiler) parent: Option<ScopeId>,
pub(in crate::engine::compiler) kind: ScopeKind,
pub(in crate::engine::compiler) is_parameter_initializer: bool,
pub(in crate::engine::compiler) bindings: Vec<BindingId>,
pub(in crate::engine::compiler) bindings_by_name: Option<Box<FxHashMap<NameId, BindingId>>>,
}
impl IrScope {
pub(in crate::engine::compiler) fn binding_named(
&self,
name: NameId,
bindings: &[IrBinding],
) -> Option<BindingId> {
if let Some(index) = &self.bindings_by_name {
return index.get(&name).copied();
}
self.bindings.iter().rev().copied().find(|id| {
bindings
.get(id.0)
.is_some_and(|binding| binding.name == name)
})
}
pub(in crate::engine::compiler) fn index_binding(
&mut self,
name: NameId,
binding: BindingId,
bindings: &[IrBinding],
) {
if let Some(index) = &mut self.bindings_by_name {
index.insert(name, binding);
} else if self.bindings.len() > 8 {
self.rebuild_name_index(bindings);
}
}
pub(in crate::engine::compiler) fn rebuild_name_index(&mut self, bindings: &[IrBinding]) {
if self.bindings.len() <= 8 {
self.bindings_by_name = None;
return;
}
let index = self.bindings_by_name.get_or_insert_with(Box::default);
index.clear();
for &binding in &self.bindings {
index.insert(bindings[binding.0].name, binding);
}
}
}