luallaby 0.1.0-alpha.3

**Work in progress** A pure-Rust Lua interpreter/compiler
Documentation
use crate::ast::Stat;
use crate::compiler::{Compiler, ScopeType};
use crate::error::Result;
use crate::vm::{OpCode, Value, VarType};

impl<'a> Compiler<'a> {
    pub(super) fn compile_stat(&mut self, stat: Stat) -> Result<()> {
        match stat {
            Stat::Nop => {}
            Stat::Ass(ass) => self.compile_ass(ass)?,
            Stat::Call(pos, exp, args) => {
                let reg_ret = self.compile_call(pos, exp, args)?;
                self.scopes.reg_free(reg_ret);
            }
            Stat::CallMethod(pos, prefix, name, args) => {
                let reg_ret = self.compile_call_method(pos, *prefix, name, args)?;
                self.scopes.reg_free(reg_ret);
            }
            Stat::Func(prefix, name, func) => {
                let src_reg = self.compile_func(func)?;
                match prefix {
                    Some(prefix) => {
                        let tbl_reg = self.compile_prefix_exp(prefix)?;
                        let ind_reg = self.scopes.reg_reserve();
                        self.code.emit(OpCode::Lit {
                            val: Value::String(name),
                            dst_reg: ind_reg,
                        });
                        self.code.emit(OpCode::TableSet {
                            src_reg,
                            tbl_reg,
                            ind_reg,
                        });
                        self.scopes.reg_free(ind_reg);
                        self.scopes.reg_free(tbl_reg);
                    }
                    None => match self.scopes.get(&name) {
                        Some((var, _)) => self.code.emit(match var {
                            VarType::Local(dst_loc) => OpCode::LocalSet { src_reg, dst_loc },
                            VarType::Up(dst_up) => OpCode::UpSet { src_reg, dst_up },
                        }),
                        None => self.code.emit(OpCode::GlobalSet { src_reg, name }),
                    },
                }
                self.scopes.reg_free(src_reg);
            }
            Stat::LocalFunc(name, func) => {
                let src_reg = self.compile_func(func)?;
                let dst_loc = self.declare_local(name, None);
                self.code.emit(OpCode::LocalSet { src_reg, dst_loc });
                self.scopes.reg_free(src_reg);
            }
            Stat::Local(local) => self.compile_local(local)?,
            Stat::Do(block) => {
                self.scope_enter(ScopeType::Do);

                self.compile_block(block)?;

                self.scope_leave(ScopeType::Do)?;
            }
            Stat::If(iff) => {
                self.compile_if(iff)?;
            }
            Stat::Break => {
                // Jump to end of loop, placeholder
                let pos = self.code.pos();
                self.code.emit(OpCode::JumpClose {
                    loc_from: 0,
                    off: 0,
                });
                self.scopes.break_insert(pos);
            }
            Stat::While(r#while) => {
                self.compile_while(r#while)?;
            }
            Stat::Repeat(repeat) => {
                self.compile_repeat(repeat)?;
            }
            Stat::For(r#for) => {
                self.compile_for(r#for)?;
            }
            Stat::Goto(label) => {
                self.scopes.goto_insert(label, self.code.pos());
                self.code.emit(OpCode::JumpClose {
                    loc_from: 0,
                    off: 0,
                }); // Placeholder
            }
            Stat::Label(label) => {
                self.scopes.label_insert(label, self.code.pos())?;
            }
        }
        Ok(())
    }
}