use crate::ast::If;
use crate::compiler::{offset, Compiler, ScopeType};
use crate::error::Result;
use crate::vm::OpCode;
impl<'a> Compiler<'a> {
pub(super) fn compile_if(&mut self, iff: If) -> Result<()> {
let mut jump_to_ends = Vec::new();
for (exp, block) in iff.conds.into_iter() {
let exp_reg = self.compile_exp(exp)?;
let jump_next = self.code.pos();
self.code.emit(OpCode::Jump { off: 0 }); self.scopes.reg_free(exp_reg);
self.scope_enter(ScopeType::Do);
self.compile_block(block)?;
self.scope_leave(ScopeType::Do)?;
let jump_end = self.code.pos();
self.code.emit(OpCode::Jump { off: 0 });
jump_to_ends.push(jump_end);
let off = offset(jump_next, self.code.pos());
self.code.set(
jump_next,
OpCode::JumpIfNot {
cmp_reg: exp_reg, off,
},
);
}
if let Some(block) = iff.els {
self.scope_enter(ScopeType::Do);
self.compile_block(*block)?;
self.scope_leave(ScopeType::Do)?;
}
let end = self.code.pos();
for jump in jump_to_ends.into_iter() {
let off = offset(jump, end);
self.code.set(jump, OpCode::Jump { off });
}
Ok(())
}
}