gbf_core/instruction.rs
1#![deny(missing_docs)]
2
3use serde::{Deserialize, Serialize};
4
5use crate::opcode::Opcode;
6use crate::operand::Operand;
7use crate::utils::Gs2BytecodeAddress;
8
9/// Represents an instruction in a bytecode system.
10#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
11pub struct Instruction {
12 /// The opcode of the instruction.
13 pub opcode: Opcode,
14
15 /// The address of the instruction.
16 pub address: Gs2BytecodeAddress,
17
18 /// The operand of the instruction, if any.
19 pub operand: Option<Operand>,
20}
21
22impl Instruction {
23 /// Create a new `Instruction`.
24 ///
25 /// # Arguments
26 /// - `opcode`: The opcode of the instruction.
27 /// - `address`: The address of the instruction.
28 ///
29 /// # Returns
30 /// - A new `Instruction` instance.
31 pub fn new(opcode: Opcode, address: usize) -> Self {
32 Self {
33 opcode,
34 address,
35 operand: None,
36 }
37 }
38
39 /// Create a new `Instruction` with an operand.
40 ///
41 /// # Arguments
42 /// - `opcode`: The opcode of the instruction.
43 /// - `address`: The address of the instruction.
44 /// - `operand`: The operand of the instruction.
45 ///
46 /// # Returns
47 /// - A new `Instruction` instance.
48 pub fn new_with_operand(opcode: Opcode, address: usize, operand: Operand) -> Self {
49 Self {
50 opcode,
51 address,
52 operand: Some(operand),
53 }
54 }
55
56 /// Set the operand of the instruction.
57 ///
58 /// # Arguments
59 /// - `operand`: The operand to set.
60 ///
61 /// # Example
62 /// ```
63 /// use gbf_core::instruction::Instruction;
64 /// use gbf_core::operand::Operand;
65 /// use gbf_core::opcode::Opcode;
66 ///
67 /// let mut instruction = Instruction::new(Opcode::PushNumber, 0);
68 /// instruction.set_operand(Operand::new_number(42));
69 /// ```
70 pub fn set_operand(&mut self, operand: Operand) {
71 self.operand = Some(operand);
72 }
73}
74
75/// Implement the `Display` trait for `Instruction`.
76impl std::fmt::Display for Instruction {
77 /// Convert the Instruction to a string
78 ///
79 /// # Returns
80 /// - A string representation of the instruction.
81 ///
82 /// # Example
83 /// ```
84 /// use gbf_core::instruction::Instruction;
85 /// use gbf_core::operand::Operand;
86 /// use gbf_core::opcode::Opcode;
87 ///
88 /// let instruction = Instruction::new_with_operand(Opcode::PushNumber, 0, Operand::new_number(42));
89 /// let string = instruction.to_string();
90 /// assert_eq!(string, "PushNumber 0x2a");
91 /// ```
92 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
93 match &self.operand {
94 Some(operand) => write!(f, "{} {}", self.opcode, operand),
95 None => write!(f, "{}", self.opcode),
96 }
97 }
98}
99
100impl Default for Instruction {
101 fn default() -> Self {
102 Self {
103 // TODO: Change this to a more appropriate default opcode
104 opcode: Opcode::ConvertToFloat,
105 address: 0,
106 operand: None,
107 }
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114 use crate::opcode::Opcode;
115
116 #[test]
117 fn instruction_to_string() {
118 let instruction = Instruction::new(Opcode::PushNumber, 0);
119 assert_eq!(instruction.to_string(), "PushNumber");
120
121 let instruction =
122 Instruction::new_with_operand(Opcode::PushNumber, 0, Operand::new_number(42));
123 assert_eq!(instruction.to_string(), "PushNumber 0x2a");
124
125 let instruction = Instruction::new_with_operand(
126 Opcode::PushString,
127 0,
128 Operand::new_string("Hello, world!"),
129 );
130 assert_eq!(instruction.to_string(), "PushString Hello, world!");
131
132 let instruction =
133 Instruction::new_with_operand(Opcode::PushNumber, 0, Operand::new_float("3.14"));
134 assert_eq!(instruction.to_string(), "PushNumber 3.14");
135 }
136}