use crate::{
binding::Binding,
expr::Expr,
function::builtin::BUILTIN_FUNCTIONS,
ident::Ident,
state::{FmtState, Interner},
utils::write_indent,
value::Value,
};
type Bindings = indexmap::IndexMap<Ident, Binding>;
type LookupStack = std::collections::HashSet<Ident>;
#[derive(Debug, Default, Clone)]
pub struct Context {
parent_ctx_idx: Option<usize>,
bindings: Bindings,
lookup_stack: LookupStack,
}
impl Context {
pub(crate) fn root(interner: &mut Interner) -> Self {
let bindings = Bindings::from_iter(BUILTIN_FUNCTIONS.into_iter().map(|(name, func)| {
(
Ident::using_interner(name, interner),
Binding::Expr(Expr::Fn(func)),
)
}));
Self {
parent_ctx_idx: None,
bindings,
lookup_stack: LookupStack::new(),
}
}
pub(crate) fn parent_ctx_idx(&self) -> Option<usize> {
self.parent_ctx_idx
}
pub(crate) fn from_iter<T, B>(parent_ctx_idx: Option<usize>, iter: T) -> Self
where
T: IntoIterator<Item = (Ident, B)>,
B: Into<Binding>,
{
Self {
parent_ctx_idx,
bindings: Bindings::from_iter(iter.into_iter().map(|(k, b)| (k, b.into()))),
lookup_stack: LookupStack::new(),
}
}
pub(crate) fn assign_from_iter<T, B>(&mut self, iter: T)
where
T: IntoIterator<Item = B>,
B: Into<Binding>,
{
let mut iter = iter.into_iter();
for (_, binding) in &mut self.bindings {
let b = unsafe { iter.next().unwrap_unchecked() };
*binding = b.into();
}
}
pub(crate) fn reassign_default_expr(&mut self) {
self.iter_mut()
.for_each(|(_, binding)| *binding = Binding::default());
}
pub(crate) fn initiate_lookup(&mut self, ident: &Ident) -> bool {
self.lookup_stack.insert(ident.to_owned())
}
pub(crate) fn conclude_lookup(&mut self, ident: &Ident) {
self.lookup_stack.remove(ident);
}
pub(crate) fn cache(&mut self, ident: &Ident, value: Value) {
self[ident] = Binding::Cached(value)
}
pub(crate) fn format<W: std::fmt::Write>(
&self,
writer: &mut W,
state: FmtState,
) -> std::fmt::Result {
for (name, expr) in &self.bindings {
if state.pretty() {
write_indent(writer, state.indent_level())?;
}
name.format(writer, state)?;
if state.pretty() {
write!(writer, " ")?;
}
write!(writer, "=")?;
if state.pretty() {
write!(writer, " ")?;
}
expr.format(writer, state)?;
write!(writer, ";")?;
if state.pretty() {
writeln!(writer)?;
}
}
Ok(())
}
}
impl std::ops::Deref for Context {
type Target = Bindings;
fn deref(&self) -> &Self::Target {
&self.bindings
}
}
impl std::ops::DerefMut for Context {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.bindings
}
}