use crate::gml::instruction::Instruction;
pub const CONV: u8 = 0x07;
pub const MUL: u8 = 0x08;
pub const DIV: u8 = 0x09;
pub const REM: u8 = 0x0A;
pub const MOD: u8 = 0x0B;
pub const ADD: u8 = 0x0C;
pub const SUB: u8 = 0x0D;
pub const AND: u8 = 0x0E;
pub const OR: u8 = 0x0F;
pub const XOR: u8 = 0x10;
pub const NEG: u8 = 0x11;
pub const NOT: u8 = 0x12;
pub const SHL: u8 = 0x13;
pub const SHR: u8 = 0x14;
pub const CMP: u8 = 0x15;
pub const POP: u8 = 0x45;
pub const DUP: u8 = 0x86;
pub const RET: u8 = 0x9C;
pub const EXIT: u8 = 0x9D;
pub const POPZ: u8 = 0x9E;
pub const JMP: u8 = 0xB6;
pub const JT: u8 = 0xB7;
pub const JF: u8 = 0xB8;
pub const PUSHENV: u8 = 0xBA;
pub const POPENV: u8 = 0xBB;
pub const PUSH: u8 = 0xC0;
pub const PUSHLOC: u8 = 0xC1;
pub const PUSHGLB: u8 = 0xC2;
pub const PUSHBLTN: u8 = 0xC3;
pub const PUSHIM: u8 = 0x84;
pub const CALL: u8 = 0xD9;
pub const CALLVAR: u8 = 0x99;
pub const EXTENDED: u8 = 0xFF;
impl Instruction {
#[must_use]
pub const fn opcode(&self) -> u8 {
match self {
Self::Convert { .. } => CONV,
Self::Multiply { .. } => MUL,
Self::Divide { .. } => DIV,
Self::Remainder { .. } => REM,
Self::Modulus { .. } => MOD,
Self::Add { .. } => ADD,
Self::Subtract { .. } => SUB,
Self::And { .. } => AND,
Self::Or { .. } => OR,
Self::Xor { .. } => XOR,
Self::Negate { .. } => NEG,
Self::Not { .. } => NOT,
Self::ShiftLeft { .. } => SHL,
Self::ShiftRight { .. } => SHR,
Self::Compare { .. } => CMP,
Self::Pop { .. } | Self::PopSwap { .. } => POP,
Self::Duplicate { .. } | Self::DuplicateSwap { .. } => DUP,
Self::Return { .. } => RET,
Self::Exit { .. } => EXIT,
Self::PopDiscard { .. } => POPZ,
Self::Branch { .. } => JMP,
Self::BranchIf { .. } => JT,
Self::BranchUnless { .. } => JF,
Self::PushWithContext { .. } => PUSHENV,
Self::PopWithContext { .. } | Self::PopWithContextExit { .. } => POPENV,
Self::Push { .. } => PUSH,
Self::PushLocal { .. } => PUSHLOC,
Self::PushGlobal { .. } => PUSHGLB,
Self::PushBuiltin { .. } => PUSHBLTN,
Self::PushImmediate { .. } => PUSHIM,
Self::Call { .. } => CALL,
Self::CallVariable { .. } => CALLVAR,
Self::CheckArrayIndex
| Self::PushArrayFinal
| Self::PopArrayFinal
| Self::PushArrayContainer
| Self::SetArrayOwner
| Self::HasStaticInitialized
| Self::SetStaticInitialized
| Self::SaveArrayReference
| Self::RestoreArrayReference
| Self::IsNullishValue
| Self::PushReference { .. } => EXTENDED,
}
}
#[must_use]
pub const fn opcode_old(&self) -> u8 {
new_to_old(self.opcode())
}
}
#[must_use]
pub const fn old_to_new(opcode: u8) -> u8 {
match opcode {
0x03 => CONV,
0x04..0x11 => opcode + 4,
0x11..0x17 => CMP,
0x41 => POP,
0x82 => DUP,
0xB7 => JMP,
0xB8 => JT,
0xB9 => JF,
0xBB => PUSHENV,
0xBC => POPENV,
0x9D => RET,
0x9E => EXIT,
0x9F => POPZ,
0xDA => 0xD9,
_ => opcode,
}
}
#[must_use]
pub const fn new_to_old(opcode: u8) -> u8 {
match opcode {
CONV => CONV - 4,
MUL..=SHR => opcode - 4,
CMP => 0,
POP => 0x41,
DUP => 0x82,
PUSHIM | PUSHGLB | PUSHLOC | PUSHBLTN => PUSH,
RET => 0x9D,
EXIT => 0x9E,
POPZ => 0x9F,
JMP..=POPENV => opcode + 1,
CALL => 0xDA,
_ => opcode,
}
}
pub mod extended {
pub const CHKINDEX: i16 = -1;
pub const PUSHAF: i16 = -2;
pub const POPAF: i16 = -3;
pub const PUSHAC: i16 = -4;
pub const SETOWNER: i16 = -5;
pub const ISSTATICOK: i16 = -6;
pub const SETSTATIC: i16 = -7;
pub const SAVEAREF: i16 = -8;
pub const RESTOREAREF: i16 = -9;
pub const ISNULLISH: i16 = -10;
pub const PUSHREF: i16 = -11;
}
impl Instruction {
#[must_use]
pub const fn extended_kind(&self) -> Option<i16> {
use super::opcodes::extended;
match self {
Self::CheckArrayIndex => Some(extended::CHKINDEX),
Self::PushArrayFinal => Some(extended::PUSHAF),
Self::PopArrayFinal => Some(extended::POPAF),
Self::PushArrayContainer => Some(extended::PUSHAC),
Self::SetArrayOwner => Some(extended::SETOWNER),
Self::HasStaticInitialized => Some(extended::ISSTATICOK),
Self::SetStaticInitialized => Some(extended::SETSTATIC),
Self::SaveArrayReference => Some(extended::SAVEAREF),
Self::RestoreArrayReference => Some(extended::RESTOREAREF),
Self::IsNullishValue => Some(extended::ISNULLISH),
Self::PushReference { .. } => Some(extended::PUSHREF),
_ => None,
}
}
}