use std::cell::RefCell;
use std::rc::Rc;
use crate::code::CodeObject;
use crate::gen::ModuleMeta;
use crate::var::Variable;
use super::*;
pub struct HirLoweringRuntime<'lir> {
code: Vec<LirElement<'lir>>,
counter: LabelCounterRef,
meta: ModuleMeta,
optimizer: Box<dyn Optimizer>,
branch_stack: Vec<HirLoweringBranch>,
locals: Vec<&'lir Variable>,
loop_stack: Vec<HirLoweringRepeat>,
}
impl<'lir> HirLoweringRuntime<'lir> {
pub fn new(meta: ModuleMeta, options: CompileOptions) -> Self {
let optimizer = if options.optimize {
Box::new(StandardOptimizer::new()) as Box<dyn Optimizer>
} else {
Box::new(NoOptimizer) as Box<dyn Optimizer>
};
Self {
code: vec![],
counter: Rc::new(RefCell::new(LabelCounter::default())),
meta,
optimizer,
branch_stack: vec![],
locals: vec![],
loop_stack: vec![],
}
}
pub fn create_new_label(&mut self) -> Label {
self.counter.borrow_mut().create_new_label()
}
pub fn add_hir(&mut self, hir: &'lir Hir) -> Lovm2CompileResult<()> {
self.locals.clear();
for arg in hir.args.iter().rev() {
self.emit(LirElement::store(Scope::Local, arg));
}
hir.block.lower(self);
match self.code.last_mut() {
Some(LirElement::Ret) => {}
_ => {
self.emit(LirElement::push_constant_owned(Value::Nil));
self.emit(LirElement::Ret);
}
}
Ok(())
}
pub fn complete(mut self) -> Lovm2CompileResult<CodeObject> {
let lir_runtime = LirLoweringRuntime::from(self.meta);
self.optimizer.postprocess(&mut self.code);
lir_runtime.lower(self.code)
}
pub fn emit(&mut self, elem: LirElement<'lir>) {
if let LirElement::StoreDynamic {
ident,
scope: Scope::Local,
} = &elem
{
if !self.has_local(ident) {
self.locals.push(ident);
}
}
self.code.push(elem);
self.optimizer.transform(&mut self.code);
}
pub fn has_local(&self, var: &Variable) -> bool {
self.locals.contains(&var)
}
pub fn loop_mut(&mut self) -> Option<&mut HirLoweringRepeat> {
self.loop_stack.last_mut()
}
pub fn push_loop(&mut self) -> &HirLoweringRepeat {
self.loop_stack
.push(HirLoweringRepeat::new(self.counter.clone()));
self.loop_stack.last_mut().unwrap()
}
pub fn pop_loop(&mut self) -> Option<HirLoweringRepeat> {
self.loop_stack.pop()
}
pub fn branch_mut(&mut self) -> Option<&mut HirLoweringBranch> {
self.branch_stack.last_mut()
}
pub fn push_branch(&mut self) -> &HirLoweringBranch {
self.branch_stack
.push(HirLoweringBranch::new(self.counter.clone()));
self.branch_stack.last_mut().unwrap()
}
pub fn pop_branch(&mut self) -> Option<HirLoweringBranch> {
self.branch_stack.pop()
}
}