use crate::ast::If;
use crate::compiler::{offset, Compiler, ScopeType};
use crate::error::Result;
use crate::vm::OpCode;
impl Compiler {
pub(super) fn compile_if(&mut self, iff: If) -> Result<()> {
let mut jump_to_ends = Vec::new();
for (exp, block, pos) in iff.conds.into_iter() {
let exp_reg = self.compile_exp(exp)?;
let jump_next = self.code.current_pc();
self.code.emit(OpCode::Jump { off: 0 }, pos); self.scopes.reg_free(exp_reg);
self.scope_enter(ScopeType::Do);
self.compile_block(block)?;
self.scope_leave(ScopeType::Do, self.code.get_pos_last())?;
let jump_end = self.code.current_pc();
self.code.emit(OpCode::Jump { off: 0 }, iff.pos_end);
jump_to_ends.push(jump_end);
let off = offset(jump_next, self.code.current_pc());
self.code.set_op(
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, self.code.get_pos_last())?;
}
let end = self.code.current_pc();
for jump in jump_to_ends.into_iter() {
let off = offset(jump, end);
self.code.set_op(jump, OpCode::Jump { off });
}
Ok(())
}
}