use super::*;
#[derive(Clone, Debug)]
pub struct Initialize {
pub(crate) base: Value,
pub(crate) slots: Vec<(Expr, Expr)>,
}
impl Initialize {
pub fn new(base: Expr) -> Self {
let base = if let Expr::Value { val, .. } = base {
val
} else {
unimplemented!()
};
Self {
base,
slots: vec![],
}
}
pub fn dict() -> Self {
Self::new(Value::dict().into())
}
pub fn list() -> Self {
Self::new(Value::list().into())
}
pub fn add<T>(&mut self, val: T)
where
T: Into<Expr>,
{
if let Value::List(list) = &mut self.base {
match val.into() {
Expr::Value { val, .. } => list.push(val),
val => {
let key = list.len() as i64;
list.push(Value::Nil);
self.slots.push((key.into(), val));
}
}
} else {
unimplemented!()
}
}
pub fn add_by_key<T, U>(&mut self, key: T, val: U)
where
T: Into<Expr>,
U: Into<Expr>,
{
if let Value::Dict(dict) = &mut self.base {
match (key.into(), val.into()) {
(Expr::Value { val: key, .. }, Expr::Value { val, .. }) => {
dict.insert(key, val);
}
(key, val) => {
self.slots.push((key, val));
}
}
} else {
unimplemented!()
}
}
}
impl HirLowering for Initialize {
fn lower<'hir, 'lir>(&'hir self, runtime: &mut HirLoweringRuntime<'lir>)
where
'hir: 'lir,
{
let requires_box = matches!(&self.base, Value::Dict(_) | Value::List(_));
runtime.emit(LirElement::push_constant(&self.base));
if requires_box {
runtime.emit(LirElement::Box);
}
for (key, expr) in self.slots.iter() {
runtime.emit(LirElement::Duplicate);
key.lower(runtime);
runtime.emit(LirElement::RGet);
expr.lower(runtime);
runtime.emit(LirElement::Set);
}
}
}