cpclib_tokens/tokens/
data_access.rs

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/// Encode the way mnemonics access to data
12#[allow(missing_docs)]
13pub enum DataAccess {
14    /// We are using an indexed register associated to its index
15    IndexRegister16WithIndex(IndexRegister16, BinaryOperation, Expr),
16    IndexRegister16(IndexRegister16),
17    IndexRegister8(IndexRegister8),
18    /// Represents a standard 16 bits register
19    Register16(Register16),
20    /// Represents a standard 8 bits register
21    Register8(Register8),
22    /// Represents a memory access indexed by a register
23    MemoryRegister16(Register16),
24    MemoryIndexRegister16(IndexRegister16),
25    /// Represents any expression
26    Expression(Expr),
27    /// Represents an address
28    Memory(Expr),
29    /// Represnts the test of bit flag
30    FlagTest(FlagTest),
31    /// Special register I
32    SpecialRegisterI,
33    /// Special register R
34    SpecialRegisterR,
35    /// Used for in/out instructions
36    PortC,
37    /// Used for in/out instructions
38    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           // impl DataAccess {
173                /// Check if this DataAccess corresonds to $reg
174                fn [<is_register_ $reg:lower>] (&self) -> bool {
175                    match self {
176                        Self::IndexRegister8(IndexRegister8::$reg, ..) => true,
177                        _ => false,
178                    }
179                }
180            }
181      //  }
182    )*}
183}
184
185#[macro_export]
186macro_rules! data_access_is_any_register8 {
187    ($($reg:ident)*) => {$(
188        paste::paste! {
189          //  impl DataAccess {
190                /// Check if this DataAccess corresonds to $reg
191                fn [<is_register_ $reg:lower>] (&self) -> bool {
192                    match self {
193                        Self::Register8(Register8::$reg, ..) => true,
194                        _ => false,
195                    }
196                }
197            }
198     //   }
199    )*}
200}
201
202#[macro_export]
203macro_rules! data_access_is_any_register16 {
204    ($($reg:ident)*) => {$(
205        paste::paste! {
206         //   impl DataAccess {
207                /// Check if this DataAccess corresonds to $reg
208                fn [<is_register_ $reg:lower>] (&self) -> bool {
209                    match self {
210                        Self::Register16(Register16::$reg, ..) => true,
211                        _ => false,
212                    }
213                }
214       //     }
215        }
216    )*}
217}
218
219#[macro_export]
220macro_rules! data_access_is_any_indexregister16 {
221    ($($reg:ident)*) => {$(
222        paste::paste! {
223       //     impl DataAccess {
224                /// Check if this DataAccess corresonds to $reg
225                fn [<is_register_ $reg:lower>] (&self) -> bool {
226                    match self {
227                        Self::IndexRegister16(IndexRegister16::$reg, ..) => true,
228                        _ => false,
229                    }
230                }
231         //   }
232        }
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}