luallaby 0.1.0-alpha.3

**Work in progress** A pure-Rust Lua interpreter/compiler
Documentation
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();

        // if and elseif blocks
        for (exp, block) in iff.conds.into_iter() {
            // Condition
            let exp_reg = self.compile_exp(exp)?;

            // Jump to next block if condition is false, placeholder
            let jump_next = self.code.pos();
            self.code.emit(OpCode::Jump { off: 0 }); // Placeholder
            self.scopes.reg_free(exp_reg);

            self.scope_enter(ScopeType::Do);

            self.compile_block(block)?;

            self.scope_leave(ScopeType::Do)?;

            // Jump to end, placeholder
            // In case of a single if block this is redundant, but don't care
            let jump_end = self.code.pos();
            self.code.emit(OpCode::Jump { off: 0 });
            jump_to_ends.push(jump_end);

            // Fill jump to next block
            let off = offset(jump_next, self.code.pos());
            self.code.set(
                jump_next,
                OpCode::JumpIfNot {
                    cmp_reg: exp_reg, // exp_reg value is valid at point of insertion
                    off,
                },
            );
        }

        // else block
        if let Some(block) = iff.els {
            self.scope_enter(ScopeType::Do);

            self.compile_block(*block)?;

            self.scope_leave(ScopeType::Do)?;
        }

        // resolve jump to ends
        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(())
    }
}