use crate::ksm::errors::InstrParseError;
use crate::ksm::sections::ArgIndex;
use crate::ksm::IntSize;
use crate::{BufferIterator, FromBytes, Opcode, ToBytes};
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Instr {
ZeroOp(Opcode),
OneOp(Opcode, ArgIndex),
TwoOp(Opcode, ArgIndex, ArgIndex),
}
impl Instr {
pub fn write(&self, buf: &mut Vec<u8>, index_bytes: IntSize) {
match self {
Instr::ZeroOp(opcode) => {
opcode.to_bytes(buf);
}
Instr::OneOp(opcode, op1) => {
opcode.to_bytes(buf);
op1.write(buf, index_bytes);
}
Instr::TwoOp(opcode, op1, op2) => {
opcode.to_bytes(buf);
op1.write(buf, index_bytes);
op2.write(buf, index_bytes);
}
}
}
pub fn parse(
source: &mut BufferIterator,
index_bytes: IntSize,
) -> Result<Self, InstrParseError> {
let opcode = Opcode::from_bytes(source)
.map_err(|e| InstrParseError::OpcodeParseError(source.current_index(), e))?;
Ok(match opcode.num_operands() {
0 => Instr::ZeroOp(opcode),
1 => {
let op1 = ArgIndex::parse(source, index_bytes)
.map_err(|_| InstrParseError::MissingOperand(1))?;
Instr::OneOp(opcode, op1)
}
2 => {
let op1 = ArgIndex::parse(source, index_bytes)
.map_err(|_| InstrParseError::MissingOperand(1))?;
let op2 = ArgIndex::parse(source, index_bytes)
.map_err(|_| InstrParseError::MissingOperand(2))?;
Instr::TwoOp(opcode, op1, op2)
}
_ => unreachable!(),
})
}
pub fn size_bytes(&self, index_bytes: IntSize) -> usize {
match self {
Self::ZeroOp(_) => 1,
Self::OneOp(_, _) => 1 + u8::from(index_bytes) as usize,
Self::TwoOp(_, _, _) => 1 + 2 * (u8::from(index_bytes) as usize),
}
}
pub fn opcode(&self) -> Opcode {
match self {
Self::ZeroOp(opcode) => *opcode,
Self::OneOp(opcode, _) => *opcode,
Self::TwoOp(opcode, _, _) => *opcode,
}
}
}