1use std::borrow::Cow;
2use std::fmt;
3use std::fmt::{Debug, Display};
4
5use paste;
6
7use crate::tokens::expression::*;
8use crate::tokens::registers::*;
9
10#[derive(Debug, PartialEq, Eq, Clone, Hash)]
11#[allow(missing_docs)]
13pub enum DataAccess {
14 IndexRegister16WithIndex(IndexRegister16, BinaryOperation, Expr),
16 IndexRegister16(IndexRegister16),
17 IndexRegister8(IndexRegister8),
18 Register16(Register16),
20 Register8(Register8),
22 MemoryRegister16(Register16),
24 MemoryIndexRegister16(IndexRegister16),
25 Expression(Expr),
27 Memory(Expr),
29 FlagTest(FlagTest),
31 SpecialRegisterI,
33 SpecialRegisterR,
35 PortC,
37 PortN(Expr)
39}
40
41impl From<u8> for DataAccess {
42 fn from(val: u8) -> Self {
43 DataAccess::Expression(Expr::from(val))
44 }
45}
46
47impl From<Expr> for DataAccess {
48 fn from(exp: Expr) -> Self {
49 DataAccess::Expression(exp)
50 }
51}
52
53impl From<&str> for DataAccess {
54 fn from(txt: &str) -> Self {
55 DataAccess::Expression(Expr::from(txt))
56 }
57}
58
59impl From<Register8> for DataAccess {
60 fn from(reg: Register8) -> Self {
61 DataAccess::Register8(reg)
62 }
63}
64
65impl From<Register16> for DataAccess {
66 fn from(reg: Register16) -> Self {
67 DataAccess::Register16(reg)
68 }
69}
70
71impl From<IndexRegister8> for DataAccess {
72 fn from(reg: IndexRegister8) -> Self {
73 DataAccess::IndexRegister8(reg)
74 }
75}
76
77impl From<IndexRegister16> for DataAccess {
78 fn from(reg: IndexRegister16) -> Self {
79 DataAccess::IndexRegister16(reg)
80 }
81}
82
83impl From<FlagTest> for DataAccess {
84 fn from(test: FlagTest) -> Self {
85 DataAccess::FlagTest(test)
86 }
87}
88
89impl fmt::Display for DataAccess {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 match self {
92 DataAccess::IndexRegister16WithIndex(reg, op, delta) => {
93 write!(f, "({reg} {op} {delta})")
94 },
95 DataAccess::IndexRegister16(reg) => write!(f, "{reg}"),
96 DataAccess::Register16(reg) => write!(f, "{reg}"),
97 DataAccess::IndexRegister8(reg) => write!(f, "{reg}"),
98 DataAccess::Register8(reg) => write!(f, "{reg}"),
99 DataAccess::MemoryRegister16(reg) => write!(f, "({reg})"),
100 DataAccess::MemoryIndexRegister16(reg) => write!(f, "({reg})"),
101 DataAccess::Expression(exp) => write!(f, "{}", exp.to_simplified_string()),
102 DataAccess::Memory(exp) => write!(f, "({})", exp.to_simplified_string()),
103 DataAccess::FlagTest(test) => write!(f, "{test}"),
104 DataAccess::SpecialRegisterI => write!(f, "I"),
105 DataAccess::SpecialRegisterR => write!(f, "R"),
106 DataAccess::PortC => write!(f, "(C)"),
107 DataAccess::PortN(n) => write!(f, "({n})")
108 }
109 }
110}
111
112pub trait DataAccessElem: Sized + Debug + Display {
113 type Expr: ExprElement;
114
115 fn get_expression(&self) -> Option<&Self::Expr>;
116 fn get_flag_test(&self) -> Option<FlagTest>;
117 fn get_index(&self) -> Option<(BinaryOperation, &Self::Expr)>;
118 fn get_indexregister16(&self) -> Option<IndexRegister16>;
119 fn get_indexregister8(&self) -> Option<IndexRegister8>;
120 fn get_register16(&self) -> Option<Register16>;
121 fn get_register8(&self) -> Option<Register8>;
122
123 #[inline]
124 fn is_flag_test(&self) -> bool {
125 self.get_flag_test().is_some()
126 }
127
128 fn is_address_in_indexregister16(&self) -> bool;
129 fn is_address_in_register16(&self) -> bool;
130 #[inline]
131 fn is_address_in_hl(&self) -> bool {
132 self.is_address_in_register16() && self.get_register16() == Some(Register16::Hl)
133 }
134 fn is_indexregister_with_index(&self) -> bool;
135 fn is_indexregister16(&self) -> bool;
136 fn is_indexregister8(&self) -> bool;
137 fn is_expression(&self) -> bool;
138 fn is_memory(&self) -> bool;
139 fn is_port_c(&self) -> bool;
140 fn is_port_n(&self) -> bool;
141 fn is_register_a(&self) -> bool;
142 fn is_register_af(&self) -> bool;
143 fn is_register_b(&self) -> bool;
144 fn is_register_bc(&self) -> bool;
145 fn is_register_c(&self) -> bool;
146 fn is_register_d(&self) -> bool;
147 fn is_register_de(&self) -> bool;
148 fn is_register_e(&self) -> bool;
149 fn is_register_h(&self) -> bool;
150 fn is_register_hl(&self) -> bool;
151 fn is_register_i(&self) -> bool;
152 fn is_register_ix(&self) -> bool;
153 fn is_register_ixh(&self) -> bool;
154 fn is_register_ixl(&self) -> bool;
155 fn is_register_iy(&self) -> bool;
156 fn is_register_iyh(&self) -> bool;
157 fn is_register_iyl(&self) -> bool;
158 fn is_register_l(&self) -> bool;
159 fn is_register_r(&self) -> bool;
160 fn is_register_sp(&self) -> bool;
161 fn is_register16(&self) -> bool;
162 fn is_register8(&self) -> bool;
163 fn to_data_access_for_high_register(&self) -> Option<Self>;
164 fn to_data_access_for_low_register(&self) -> Option<Self>;
165 fn to_data_access(&self) -> Cow<DataAccess>;
166}
167
168#[macro_export]
169macro_rules! data_access_is_any_indexregister8 {
170 ($($reg:ident)*) => {$(
171 paste::paste! {
172 fn [<is_register_ $reg:lower>] (&self) -> bool {
175 match self {
176 Self::IndexRegister8(IndexRegister8::$reg, ..) => true,
177 _ => false,
178 }
179 }
180 }
181 )*}
183}
184
185#[macro_export]
186macro_rules! data_access_is_any_register8 {
187 ($($reg:ident)*) => {$(
188 paste::paste! {
189 fn [<is_register_ $reg:lower>] (&self) -> bool {
192 match self {
193 Self::Register8(Register8::$reg, ..) => true,
194 _ => false,
195 }
196 }
197 }
198 )*}
200}
201
202#[macro_export]
203macro_rules! data_access_is_any_register16 {
204 ($($reg:ident)*) => {$(
205 paste::paste! {
206 fn [<is_register_ $reg:lower>] (&self) -> bool {
209 match self {
210 Self::Register16(Register16::$reg, ..) => true,
211 _ => false,
212 }
213 }
214 }
216 )*}
217}
218
219#[macro_export]
220macro_rules! data_access_is_any_indexregister16 {
221 ($($reg:ident)*) => {$(
222 paste::paste! {
223 fn [<is_register_ $reg:lower>] (&self) -> bool {
226 match self {
227 Self::IndexRegister16(IndexRegister16::$reg, ..) => true,
228 _ => false,
229 }
230 }
231 }
233 )*}
234}
235
236#[macro_export]
237macro_rules! data_access_impl_most_methods {
238 () => {
239
240 fn get_flag_test(&self) -> Option<FlagTest> {
241 match self {
242 Self::FlagTest(test, ..) => Some(*test),
243 _ => None
244 }
245 }
246
247 fn is_register8(&self) -> bool {
248 match self {
249 Self::Register8(..) => true,
250 _ => false
251 }
252 }
253
254 fn is_register16(&self) -> bool {
255 match self {
256 Self::Register16(..) => true,
257 _ => false
258 }
259 }
260
261 fn is_indexregister8(&self) -> bool {
262 match self {
263 Self::IndexRegister8(..) => true,
264 _ => false
265 }
266 }
267
268 fn is_indexregister16(&self) -> bool {
269 match self {
270 Self::IndexRegister16(..) => true,
271 _ => false
272 }
273 }
274
275 fn is_indexregister_with_index(&self) -> bool {
276 match self {
277 Self::IndexRegister16WithIndex(..) => true,
278 _ => false
279 }
280 }
281
282 fn is_memory(&self) -> bool {
283 match self {
284 Self::Memory(..) => true,
285 _ => false
286 }
287 }
288
289 fn is_address_in_register16(&self) -> bool {
290 match self {
291 Self::MemoryRegister16(..) => true,
292 _ => false
293 }
294 }
295
296 fn is_address_in_indexregister16(&self) -> bool {
297 match self {
298 Self::MemoryIndexRegister16(..) => true,
299 _ => false
300 }
301 }
302
303 fn get_register16(&self) -> Option<Register16> {
304 match self {
305 Self::Register16( reg, ..) => Some(*reg),
306 Self::MemoryRegister16( reg, ..) => Some(*reg),
307 _ => None
308 }
309 }
310
311 fn get_indexregister16(&self) -> Option<IndexRegister16> {
312 match self {
313 Self::IndexRegister16( reg, ..) => Some(*reg),
314 Self::MemoryIndexRegister16( reg, ..) => Some(*reg),
315 Self::IndexRegister16WithIndex(reg, ..) => Some(*reg),
316 _ => None
317 }
318 }
319
320
321 fn get_register8(&self) -> Option<Register8> {
322 match self {
323 Self::Register8( reg, ..) => Some(*reg),
324 _ => None
325 }
326 }
327
328 fn get_indexregister8(&self) -> Option<IndexRegister8> {
329 match self {
330 Self::IndexRegister8( reg, ..) => Some(*reg),
331 _ => None
332 }
333 }
334
335 fn get_expression(&self) -> Option<&Self::Expr> {
336 match self {
337 Self::Expression(exp, ..) |
338 Self::Memory(exp, ..) |
339 Self::PortN(exp,..) => Some(exp),
340
341 _ => None
342 }
343 }
344
345 fn is_port_n(&self) -> bool {
346 match self {
347 Self::PortN(..) => true,
348 _ => false
349 }
350 }
351
352 fn is_expression(&self) -> bool {
353 match self {
354 Self::Expression(..) => true,
355 _ => false
356 }
357 }
358
359 fn get_index(&self) -> Option<(BinaryOperation, &Self::Expr)> {
360 match self {
361 Self::IndexRegister16WithIndex(_, op, exp, ..) => Some((*op, exp)),
362 _ => None
363 }
364 }
365
366
367
368 data_access_is_any_indexregister8!(Ixh Ixl Iyh Iyl);
369 data_access_is_any_register8!(A B C D E H L);
370 data_access_is_any_register16!(Af Bc De Hl Sp);
371 data_access_is_any_indexregister16!(Ix Iy);
372 }
373}
374
375#[allow(missing_docs)]
376impl DataAccessElem for DataAccess {
377 type Expr = Expr;
378
379 data_access_impl_most_methods!();
380
381 fn to_data_access_for_low_register(&self) -> Option<Self> {
382 match self {
383 Self::IndexRegister16(reg, ..) => Some(reg.low().into()),
384 Self::Register16(reg, ..) => Some(reg.low().unwrap().into()),
385 _ => None
386 }
387 }
388
389 fn to_data_access_for_high_register(&self) -> Option<Self> {
390 match self {
391 Self::IndexRegister16(reg, ..) => Some(reg.high().into()),
392 Self::Register16(reg, ..) => Some(reg.high().unwrap().into()),
393 _ => None
394 }
395 }
396
397 fn is_port_c(&self) -> bool {
398 match self {
399 Self::PortC => true,
400 _ => false
401 }
402 }
403
404 fn is_register_i(&self) -> bool {
405 match self {
406 Self::SpecialRegisterI => true,
407 _ => false
408 }
409 }
410
411 fn is_register_r(&self) -> bool {
412 match self {
413 Self::SpecialRegisterR => true,
414 _ => false
415 }
416 }
417
418 fn to_data_access(&self) -> Cow<DataAccess> {
419 Cow::Borrowed(self)
420 }
421}
422
423impl DataAccess {
424 fn expression_mut(&mut self) -> Option<&mut Expr> {
425 match self {
426 DataAccess::Expression(exp) => Some(exp),
427 _ => None
428 }
429 }
430
431 pub fn replace_expressions_by_0(&self) -> Self {
432 match self {
433 DataAccess::IndexRegister16WithIndex(index_register16, binary_operation, expr) => {
434 Self::IndexRegister16WithIndex(*index_register16, *binary_operation, 0.into())
435 },
436 DataAccess::IndexRegister16(r) => self.clone(),
437 DataAccess::IndexRegister8(r) => self.clone(),
438 DataAccess::Register16(register16) => self.clone(),
439 DataAccess::Register8(register8) => self.clone(),
440 DataAccess::MemoryRegister16(register16) => self.clone(),
441 DataAccess::MemoryIndexRegister16(index_register16) => self.clone(),
442 DataAccess::Expression(expr) => Self::Expression(0.into()),
443 DataAccess::Memory(expr) => DataAccess::Memory(0.into()),
444 DataAccess::FlagTest(flag_test) => self.clone(),
445 DataAccess::SpecialRegisterI => self.clone(),
446 DataAccess::SpecialRegisterR => self.clone(),
447 DataAccess::PortC => self.clone(),
448 DataAccess::PortN(expr) => DataAccess::PortN(0.into())
449 }
450 }
451}
452
453#[cfg(test)]
454mod test {
455 use super::*;
456
457 #[test]
458 fn is_indexregister8() {
459 assert!(DataAccess::IndexRegister8(IndexRegister8::Ixl).is_indexregister8());
460 assert!(DataAccess::IndexRegister8(IndexRegister8::Ixl).is_register_ixl());
461 assert!(!DataAccess::IndexRegister8(IndexRegister8::Ixl).is_register_iyl());
462 assert!(!DataAccess::Register8(Register8::A).is_register_iyl());
463 }
464}