1use std::fmt;
2
3use super::opcode::Opcode;
4
5#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
12pub struct Instruction {
13 pub op: Opcode,
14 pub a: u8,
15 pub b: u8,
16 pub c: u8,
17 pub imm: i32,
18}
19
20impl Instruction {
21 pub fn new(op: Opcode, a: u8, b: u8, c: u8, imm: i32) -> Self {
22 Instruction { op, a, b, c, imm }
23 }
24
25 pub fn nullary(op: Opcode) -> Self {
26 Instruction::new(op, 0, 0, 0, 0)
27 }
28
29 pub fn abc(op: Opcode, a: u8, b: u8, c: u8) -> Self {
30 Instruction::new(op, a, b, c, 0)
31 }
32
33 pub fn a_imm(op: Opcode, a: u8, imm: i32) -> Self {
34 Instruction::new(op, a, 0, 0, imm)
35 }
36
37 pub fn only_imm(op: Opcode, imm: i32) -> Self {
38 Instruction::new(op, 0, 0, 0, imm)
39 }
40}
41
42impl fmt::Display for Instruction {
43 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44 match self.op {
45 Opcode::Halt | Opcode::Yield | Opcode::Nop => write!(f, "{}", self.op),
46 Opcode::LoadConst => write!(f, "{} r{}, const[{}]", self.op, self.a, self.imm),
47 Opcode::Move => write!(f, "{} r{}, r{}", self.op, self.a, self.b),
48 Opcode::LoadImm => write!(f, "{} r{}, {}", self.op, self.a, self.imm),
49 Opcode::Add | Opcode::Sub | Opcode::Mul | Opcode::Div | Opcode::Mod | Opcode::Eq
50 | Opcode::Lt | Opcode::Le => {
51 write!(f, "{} r{}, r{}, r{}", self.op, self.a, self.b, self.c)
52 }
53 Opcode::Neg => write!(f, "{} r{}, r{}", self.op, self.a, self.b),
54 Opcode::Jump => write!(f, "{} {:+}", self.op, self.imm),
55 Opcode::Branch => write!(f, "{} r{}, {:+}", self.op, self.a, self.imm),
56 Opcode::Call | Opcode::CallNative => {
57 write!(f, "{} r{}, fn[{}], argc={}", self.op, self.a, self.imm, self.b)
58 }
59 Opcode::Return
60 | Opcode::Exit
61 | Opcode::Sleep
62 | Opcode::Receive
63 | Opcode::SelfPid
64 | Opcode::FreshRequestId => {
65 write!(f, "{} r{}", self.op, self.a)
66 }
67 Opcode::Spawn => write!(
68 f,
69 "{} r{}, fn[{}], argc={}, rights={:#x}",
70 self.op, self.a, self.imm, self.b, self.c
71 ),
72 Opcode::Send => write!(f, "{} r{}, r{}", self.op, self.a, self.b),
73 Opcode::ReceiveTimeout | Opcode::ReceiveMatch => {
74 write!(f, "{} r{}, r{}", self.op, self.a, self.b)
75 }
76 Opcode::ReceiveMatchImm => write!(f, "{} r{}, tag={}", self.op, self.a, self.imm),
77 Opcode::ReceiveMatchCorr => write!(
78 f,
79 "{} r{}, tag=r{}, id=r{}",
80 self.op, self.a, self.b, self.c
81 ),
82 Opcode::ReceiveMatchCorrImm => write!(
83 f,
84 "{} r{}, tag={}, id=r{}",
85 self.op, self.a, self.imm, self.b
86 ),
87 Opcode::Ask => write!(
88 f,
89 "{} r{}, r{}, r{}",
90 self.op, self.a, self.b, self.c
91 ),
92 Opcode::AskTimeout => write!(
93 f,
94 "{} r{}, r{}, r{}, timeout=r{}",
95 self.op, self.a, self.b, self.c, self.imm
96 ),
97 Opcode::Monitor | Opcode::Link => {
98 write!(f, "{} r{}, r{}", self.op, self.a, self.b)
99 }
100 Opcode::Demonitor | Opcode::Unlink | Opcode::RegisterName => {
101 write!(f, "{} r{}", self.op, self.a)
102 }
103 Opcode::Whereis => write!(f, "{} r{}, r{}", self.op, self.a, self.b),
104 Opcode::Delegate => write!(
105 f,
106 "{} r{}, r{}, rights={:#x}, native=r{}",
107 self.op, self.a, self.b, self.imm as u32, self.c
108 ),
109 Opcode::Trap => write!(f, "{} {}", self.op, self.imm),
110 }
111 }
112}