use std::fmt;
use super::opcode::Opcode;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Instruction {
pub op: Opcode,
pub a: u8,
pub b: u8,
pub c: u8,
pub imm: i32,
}
impl Instruction {
pub fn new(op: Opcode, a: u8, b: u8, c: u8, imm: i32) -> Self {
Instruction { op, a, b, c, imm }
}
pub fn nullary(op: Opcode) -> Self {
Instruction::new(op, 0, 0, 0, 0)
}
pub fn abc(op: Opcode, a: u8, b: u8, c: u8) -> Self {
Instruction::new(op, a, b, c, 0)
}
pub fn a_imm(op: Opcode, a: u8, imm: i32) -> Self {
Instruction::new(op, a, 0, 0, imm)
}
pub fn only_imm(op: Opcode, imm: i32) -> Self {
Instruction::new(op, 0, 0, 0, imm)
}
}
impl fmt::Display for Instruction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.op {
Opcode::Halt | Opcode::Yield | Opcode::Nop => write!(f, "{}", self.op),
Opcode::LoadConst => write!(f, "{} r{}, const[{}]", self.op, self.a, self.imm),
Opcode::Move => write!(f, "{} r{}, r{}", self.op, self.a, self.b),
Opcode::LoadImm => write!(f, "{} r{}, {}", self.op, self.a, self.imm),
Opcode::Add | Opcode::Sub | Opcode::Mul | Opcode::Div | Opcode::Mod | Opcode::Eq
| Opcode::Lt | Opcode::Le => {
write!(f, "{} r{}, r{}, r{}", self.op, self.a, self.b, self.c)
}
Opcode::Neg => write!(f, "{} r{}, r{}", self.op, self.a, self.b),
Opcode::Jump => write!(f, "{} {:+}", self.op, self.imm),
Opcode::Branch => write!(f, "{} r{}, {:+}", self.op, self.a, self.imm),
Opcode::Call | Opcode::CallNative => {
write!(f, "{} r{}, fn[{}], argc={}", self.op, self.a, self.imm, self.b)
}
Opcode::Return | Opcode::Exit | Opcode::Sleep | Opcode::Receive | Opcode::SelfPid => {
write!(f, "{} r{}", self.op, self.a)
}
Opcode::Spawn => write!(
f,
"{} r{}, fn[{}], argc={}",
self.op, self.a, self.imm, self.b
),
Opcode::Send => write!(f, "{} r{}, r{}", self.op, self.a, self.b),
Opcode::ReceiveTimeout | Opcode::ReceiveMatch => {
write!(f, "{} r{}, r{}", self.op, self.a, self.b)
}
Opcode::ReceiveMatchImm => write!(f, "{} r{}, tag={}", self.op, self.a, self.imm),
Opcode::Ask => write!(
f,
"{} r{}, r{}, r{}",
self.op, self.a, self.b, self.c
),
Opcode::AskTimeout => write!(
f,
"{} r{}, r{}, r{}, timeout=r{}",
self.op, self.a, self.b, self.c, self.imm
),
Opcode::Monitor | Opcode::Link => {
write!(f, "{} r{}, r{}", self.op, self.a, self.b)
}
Opcode::Demonitor | Opcode::Unlink => write!(f, "{} r{}", self.op, self.a),
Opcode::Trap => write!(f, "{} {}", self.op, self.imm),
}
}
}