use super::{VmError, VmResult};
macro_rules! ops {
($($(#[$attr:meta])* $name:ident = $val:literal),+ $(,)?) => {
#[repr(usize)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Op {
$($(#[$attr])* $name = $val,)+
}
impl TryFrom<usize> for Op {
type Error = VmError;
fn try_from(u: usize) -> VmResult<Self> {
match u {
$($val => Ok(Op::$name),)+
_ => Err(VmError::InvalidOpCode(u as u8)),
}
}
}
}
}
ops! {
Halt = 0x00,
Yield = 0x01,
Call = 0x02,
Execute = 0x03,
DoCreate = 0x04,
Exit = 0x05,
Lit = 0x06,
Str = 0x07,
Jmp = 0x08,
JmpZ = 0x09,
Do = 0x0a,
QDo = 0x0b,
PlusLoop = 0x0c,
Unloop = 0x0d,
I = 0x0e,
J = 0x0f,
Drop = 0x10,
Swap = 0x11,
Dup = 0x12,
SpFetch = 0x13,
SpStore = 0x14,
ToR = 0x15,
RFrom = 0x16,
RpFetch = 0x17,
RpStore = 0x18,
Fetch = 0x19,
Store = 0x1a,
CFetch = 0x1b,
CStore = 0x1c,
Add = 0x1d,
UmMul = 0x1e,
UmDivMod = 0x1f,
Nand = 0x20,
LShift = 0x21,
RShift = 0x22,
LtZ = 0x23,
EqZ = 0x24,
Parse = 0x25,
ParseEscaped = 0x26,
Number = 0x27,
ToNumber = 0x28,
CompileComma = 0x29,
Decode = 0x2a,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn try_from_valid() {
assert_eq!(Op::try_from(0x00).unwrap(), Op::Halt);
assert_eq!(Op::try_from(0x01).unwrap(), Op::Yield);
assert_eq!(Op::try_from(0x04).unwrap(), Op::DoCreate);
}
#[test]
fn try_from_invalid() {
assert_eq!(Op::try_from(0xfe), Err(VmError::InvalidOpCode(0xfe)));
}
}