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 => {
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,
}); }
Stat::Label(label) => {
self.scopes.label_insert(label, self.code.pos())?;
}
}
Ok(())
}
}