use std::convert::TryFrom;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum Opcode {
Pop,
Dup,
Swap,
PushZero,
PushOne,
PushInt8,
PushInt16,
PushInt32,
PushRational,
PushNaN,
PushPositiveInfinity,
PushNegativeInfinity,
PushNull,
PushTrue,
PushFalse,
PushUndefined,
PushLiteral,
PushEmptyObject,
PushNewArray,
Add,
Sub,
Div,
Mul,
Mod,
Pow,
ShiftRight,
ShiftLeft,
UnsignedShiftRight,
BitOr,
BitAnd,
BitXor,
BitNot,
In,
Eq,
StrictEq,
NotEq,
StrictNotEq,
GreaterThan,
GreaterThanOrEq,
LessThan,
LessThanOrEq,
InstanceOf,
LogicalAnd,
LogicalOr,
Coalesce,
TypeOf,
Void,
LogicalNot,
Pos,
Neg,
DefVar,
DefLet,
DefConst,
InitLexical,
GetName,
SetName,
GetPropertyByName,
GetPropertyByValue,
SetPropertyByName,
SetPropertyByValue,
Jump,
JumpIfFalse,
JumpIfTrue,
Throw,
ToBoolean,
This,
Case,
Default,
Nop,
}
impl Opcode {
pub unsafe fn from_raw(value: u8) -> Self {
std::mem::transmute(value)
}
pub fn as_str(self) -> &'static str {
match self {
Opcode::Pop => "Pop",
Opcode::Dup => "Dup",
Opcode::Swap => "Swap",
Opcode::PushZero => "PushZero",
Opcode::PushOne => "PushOne",
Opcode::PushInt8 => "PushInt8",
Opcode::PushInt16 => "PushInt16",
Opcode::PushInt32 => "PushInt32",
Opcode::PushRational => "PushRational",
Opcode::PushNaN => "PushNaN",
Opcode::PushPositiveInfinity => "PushPositiveInfinity",
Opcode::PushNegativeInfinity => "PushNegativeInfinity",
Opcode::PushNull => "PushNull",
Opcode::PushTrue => "PushTrue",
Opcode::PushFalse => "PushFalse",
Opcode::PushUndefined => "PushUndefined",
Opcode::PushLiteral => "PushLiteral",
Opcode::PushEmptyObject => "PushEmptyObject",
Opcode::PushNewArray => "PushNewArray",
Opcode::Add => "Add",
Opcode::Sub => "Sub",
Opcode::Div => "Div",
Opcode::Mul => "Mul",
Opcode::Mod => "Mod",
Opcode::Pow => "Pow",
Opcode::ShiftRight => "ShiftRight",
Opcode::ShiftLeft => "ShiftLeft",
Opcode::UnsignedShiftRight => "UnsignedShiftRight",
Opcode::BitOr => "BitOr",
Opcode::BitAnd => "BitAnd",
Opcode::BitXor => "BitXor",
Opcode::BitNot => "BitNot",
Opcode::In => "In",
Opcode::Eq => "Eq",
Opcode::StrictEq => "StrictEq",
Opcode::NotEq => "NotEq",
Opcode::StrictNotEq => "StrictNotEq",
Opcode::GreaterThan => "GreaterThan",
Opcode::GreaterThanOrEq => "GreaterThanOrEq",
Opcode::LessThan => "LessThan",
Opcode::LessThanOrEq => "LessThanOrEq",
Opcode::InstanceOf => "InstanceOf",
Opcode::TypeOf => "TypeOf",
Opcode::Void => "Void",
Opcode::LogicalNot => "LogicalNot",
Opcode::LogicalAnd => "LogicalAnd",
Opcode::LogicalOr => "LogicalOr",
Opcode::Coalesce => "Coalesce",
Opcode::Pos => "Pos",
Opcode::Neg => "Neg",
Opcode::DefVar => "DefVar",
Opcode::DefLet => "DefLet",
Opcode::DefConst => "DefConst",
Opcode::InitLexical => "InitLexical",
Opcode::GetName => "GetName",
Opcode::SetName => "SetName",
Opcode::GetPropertyByName => "GetPropertyByName",
Opcode::GetPropertyByValue => "GetPropertyByValue",
Opcode::SetPropertyByName => "SetPropertyByName",
Opcode::SetPropertyByValue => "SetPropertyByValue",
Opcode::Jump => "Jump",
Opcode::JumpIfFalse => "JumpIfFalse",
Opcode::JumpIfTrue => "JumpIfTrue",
Opcode::Throw => "Throw",
Opcode::ToBoolean => "ToBoolean",
Opcode::This => "This",
Opcode::Case => "Case",
Opcode::Default => "Default",
Opcode::Nop => "Nop",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct InvalidOpcodeError {
value: u8,
}
impl std::fmt::Display for InvalidOpcodeError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "invalid opcode: {:#04x}", self.value)
}
}
impl std::error::Error for InvalidOpcodeError {}
impl TryFrom<u8> for Opcode {
type Error = InvalidOpcodeError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
if value > Self::Nop as u8 {
return Err(InvalidOpcodeError { value });
}
let opcode = unsafe { Self::from_raw(value) };
Ok(opcode)
}
}