1use core::fmt;
2
3use crate::{helper::case_insensitive::Str, num3::ThreeDigitNumber};
4
5#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
6#[repr(u16)]
7pub enum Instruction<Data> {
9 ADD(Data) = 100,
11 SUB(Data) = 200,
14
15 STO(Data) = 300,
17 LDA(Data) = 500,
19
20 BR(Data) = 600,
22 BRZ(Data) = 700,
24 BRP(Data) = 800,
26
27 IN = 901,
29 OUT = 902,
31 #[cfg(feature = "extended")]
32 INA = 911,
34 #[cfg(feature = "extended")]
35 OUTA = 912,
37
38 #[default]
39 HLT = 1,
41
42 #[cfg(feature = "extended")]
43 EXT = 10,
45
46 DAT(Data) = 0,
48}
49
50impl<Data> Instruction<Data> {
51 pub const fn op_code(&self) -> ThreeDigitNumber {
53 let op_code = unsafe { *(self as *const Self).cast::<u16>() };
54 if op_code == 1 {
55 ThreeDigitNumber::ZERO
56 } else {
57 unsafe { ThreeDigitNumber::from_unchecked(op_code) }
58 }
59 }
60}
61
62#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
63pub struct InstructionWithLabel<'a, Data> {
64 pub label: Option<&'a str>,
65 pub instruction: Instruction<Data>,
66}
67
68pub type RawInstruction = Instruction<ThreeDigitNumber>;
69
70#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
71pub enum NumberOrLabel<'a> {
72 Number(ThreeDigitNumber),
73 Label(&'a str),
74}
75
76#[derive(Clone, Copy, Debug, PartialEq, Eq)]
77pub enum InvalidInstructionError {
78 InvalidInstruction,
79}
80
81impl fmt::Display for InvalidInstructionError {
82 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83 match self {
84 Self::InvalidInstruction => write!(f, "Failed to parse an unknown instruction!"),
85 }
86 }
87}
88
89#[cfg(feature = "std")]
90impl std::error::Error for InvalidInstructionError {}
91
92impl TryFrom<&str> for Instruction<()> {
93 type Error = InvalidInstructionError;
94
95 fn try_from(value: &str) -> Result<Self, Self::Error> {
96 match Str::from(value) {
97 i if i == "ADD" => Ok(Self::ADD(())),
98 i if i == "SUB" => Ok(Self::SUB(())),
99
100 i if i == "STO" || i == "STA" => Ok(Self::STO(())),
101 i if i == "LDA" => Ok(Self::LDA(())),
102
103 i if i == "BR" || i == "BRA" => Ok(Self::BR(())),
104 i if i == "BRZ" => Ok(Self::BRZ(())),
105 i if i == "BRP" => Ok(Self::BRP(())),
106
107 i if i == "IN" || i == "INP" => Ok(Self::IN),
108 i if i == "OUT" => Ok(Self::OUT),
109 #[cfg(feature = "extended")]
110 i if i == "INA" => Ok(Self::INA),
111 #[cfg(feature = "extended")]
112 i if i == "OTA" => Ok(Self::OUTA),
113
114 i if i == "HLT" => Ok(Self::HLT),
115
116 #[cfg(feature = "extended")]
117 i if i == "EXT" => Ok(Self::EXT),
118
119 i if i == "DAT" => Ok(Self::DAT(())),
120
121 _ => Err(InvalidInstructionError::InvalidInstruction),
122 }
123 }
124}
125
126impl<'a> From<&'a str> for NumberOrLabel<'a> {
127 fn from(value: &'a str) -> Self {
128 value
129 .parse::<u16>()
130 .ok()
131 .and_then(|number| ThreeDigitNumber::try_from(number).ok())
132 .map_or(Self::Label(value), Self::Number)
133 }
134}
135
136#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
137pub enum Error {
139 ExpectedData,
141 UnexpectedData,
143}
144
145impl fmt::Display for Error {
146 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147 match self {
148 Self::ExpectedData => write!(f, "Expected label / number!"),
149 Self::UnexpectedData => write!(f, "Unexpected label / number!"),
150 }
151 }
152}
153
154#[cfg(feature = "std")]
155impl std::error::Error for Error {}
156
157impl Instruction<()> {
158 #[allow(clippy::missing_const_for_fn)]
160 pub fn try_insert_data<Data>(self, data: Option<Data>) -> Result<Instruction<Data>, Error> {
165 use Error::{ExpectedData, UnexpectedData};
166 #[cfg(feature = "extended")]
167 use Instruction::{ADD, BR, BRP, BRZ, DAT, EXT, HLT, IN, INA, LDA, OUT, OUTA, STO, SUB};
168 #[cfg(not(feature = "extended"))]
169 use Instruction::{ADD, BR, BRP, BRZ, DAT, HLT, IN, LDA, OUT, STO, SUB};
170
171 match (self, data) {
172 (ADD(()), Some(data)) => Ok(ADD(data)),
173 (ADD(()), None) => Err(ExpectedData),
174 (SUB(()), Some(data)) => Ok(SUB(data)),
175 (SUB(()), None) => Err(ExpectedData),
176
177 (STO(()), Some(data)) => Ok(STO(data)),
178 (STO(()), None) => Err(ExpectedData),
179 (LDA(()), Some(data)) => Ok(LDA(data)),
180 (LDA(()), None) => Err(ExpectedData),
181
182 (BR(()), Some(data)) => Ok(BR(data)),
183 (BR(()), None) => Err(ExpectedData),
184 (BRP(()), Some(data)) => Ok(BRP(data)),
185 (BRP(()), None) => Err(ExpectedData),
186 (BRZ(()), Some(data)) => Ok(BRZ(data)),
187 (BRZ(()), None) => Err(ExpectedData),
188
189 (IN, Some(_)) => Err(UnexpectedData),
190 (IN, None) => Ok(IN),
191 (OUT, Some(_)) => Err(UnexpectedData),
192 (OUT, None) => Ok(OUT),
193 #[cfg(feature = "extended")]
194 (INA, Some(_)) => Err(UnexpectedData),
195 #[cfg(feature = "extended")]
196 (INA, None) => Ok(INA),
197 #[cfg(feature = "extended")]
198 (OUTA, Some(_)) => Err(UnexpectedData),
199 #[cfg(feature = "extended")]
200 (OUTA, None) => Ok(OUTA),
201
202 (HLT, Some(_)) => Err(UnexpectedData),
203 (HLT, None) => Ok(HLT),
204
205 #[cfg(feature = "extended")]
206 (EXT, Some(_)) => Err(UnexpectedData),
207 #[cfg(feature = "extended")]
208 (EXT, None) => Ok(EXT),
209
210 (DAT(()), Some(data)) => Ok(DAT(data)),
211 (DAT(()), None) => Err(ExpectedData),
212 }
213 }
214}
215
216impl<Data> Instruction<Data> {
217 pub const fn add_label(self, label: Option<&str>) -> InstructionWithLabel<Data> {
219 InstructionWithLabel {
220 label,
221 instruction: self,
222 }
223 }
224}