use self::OpCode::*;
#[cfg(test)]
mod tests;
pub type Args = (u32, u32, u32);
pub trait Register: std::ops::IndexMut<u32, Output = u32> + Sized {
fn exec_copy(&self, op: OpCode, (a, b, c): Args) -> Self
where
Self: Clone,
{
let mut copy = self.clone();
copy[c] = copy.exec_binop(op, a, b);
copy
}
fn exec(&mut self, op: OpCode, (a, b, c): Args) {
self[c] = self.exec_binop(op, a, b)
}
fn exec_binop(&self, op: OpCode, a: u32, b: u32) -> u32 {
let reg = |i| self[i];
match op {
OpCode::AddI => reg(a) + b,
OpCode::AddR => reg(a) + reg(b),
OpCode::MulI => reg(a) * b,
OpCode::MulR => reg(a) * reg(b),
OpCode::BAnI => reg(a) & b,
OpCode::BAnR => reg(a) & reg(b),
OpCode::BOrI => reg(a) | b,
OpCode::BOrR => reg(a) | reg(b),
OpCode::SetI => a,
OpCode::SetR => reg(a),
OpCode::GtIR => {
if a > reg(b) {
1
} else {
0
}
}
OpCode::GtRI => {
if reg(a) > b {
1
} else {
0
}
}
OpCode::GtRR => {
if reg(a) > reg(b) {
1
} else {
0
}
}
OpCode::EqIR => {
if a == reg(b) {
1
} else {
0
}
}
OpCode::EqRI => {
if reg(a) == b {
1
} else {
0
}
}
OpCode::EqRR => {
if reg(a) == reg(b) {
1
} else {
0
}
}
}
}
}
impl OpCode {
pub const OPCODES: [OpCode; 16] = [
AddI, AddR, MulI, MulR, BAnI, BAnR, BOrI, BOrR, SetI, SetR, GtIR, GtRI, GtRR, EqIR, EqRI, EqRR, ];
pub fn iter() -> impl Iterator<Item = OpCode> {
Self::OPCODES.iter().cloned()
}
}
#[derive(Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Debug)]
pub enum OpCode {
AddR,
AddI,
MulR,
MulI,
BAnR,
BAnI,
BOrR,
BOrI,
SetR,
SetI,
GtIR,
GtRI,
GtRR,
EqIR,
EqRI,
EqRR,
}
impl OpCode {
pub fn from_name(s: &str) -> Option<Self> {
Some(match s {
"addi" => AddI,
"addr" => AddR,
"muli" => MulI,
"mulr" => MulR,
"bani" => BAnI,
"banr" => BAnR,
"bori" => BOrI,
"borr" => BOrR,
"seti" => SetI,
"setr" => SetR,
"gtir" => GtIR,
"gtri" => GtRI,
"gtrr" => GtRR,
"eqir" => EqIR,
"eqri" => EqRI,
"eqrr" => EqRR,
_ => return None,
})
}
}
impl Into<&'static str> for OpCode {
fn into(self) -> &'static str {
match self {
AddI => "addi",
AddR => "addr",
MulI => "muli",
MulR => "mulr",
BAnI => "bani",
BAnR => "banr",
BOrI => "bori",
BOrR => "borr",
SetI => "seti",
SetR => "setr",
GtIR => "gtir",
GtRI => "gtri",
GtRR => "gtrr",
EqIR => "eqir",
EqRI => "eqri",
EqRR => "eqrr",
}
}
}