// © 2023 John Breaux //! A [SecondaryOperand] contains the second [Register], addressing mode, and Extension //! Word for a [two-operand](Encoding::Double) [instruction] use super::*; /// The destination of a [Double](Encoding::Double) #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum SecondaryOperand { Direct(Register), Indexed(Register, Number), Absolute(Number), // Joke encodings? Zero, One, } impl SecondaryOperand { pub fn mode(&self) -> u16 { use SecondaryOperand::*; match self { Direct(_) | Zero => 0, Indexed(_, _) | Absolute(_) | One => 1 << 7, } } pub fn register(&self) -> Register { use SecondaryOperand::*; match self { Direct(r) | Indexed(r, _) => *r, Absolute(_) => Register::sr, Zero | One => Register::cg, } } /// This is the only way to have an extension word pub fn ext_word(&self) -> Option { use SecondaryOperand::*; match self { Indexed(_, w) | Absolute(w) => Some((*w).into()), _ => None, } } } impl Parsable for SecondaryOperand { // Separator // - Register => Direct // - Number => Indexed // - OpenIdx // - Register // - CloseIdx // - Absolute // - Number // - Immediate // - Number == 0, 1 fn parse<'text, T>(p: &Parser, stream: &mut T) -> Result where T: crate::TokenStream<'text> { use SecondaryOperand::*; stream.allow(Type::Separator); // Try parsing as Register Direct if let Some(r) = Register::try_parse(p, stream)? { return Ok(Self::Direct(r)); } // Try parsing as Number Indexed if let Some(idx) = Number::try_parse(p, stream)? { stream.expect(Type::LParen)?; let reg = Register::parse(p, stream)?; stream.expect(Type::RParen)?; return Ok(Self::Indexed(reg, idx)); } let token = stream.expect_any_of([Type::Absolute, Type::Immediate])?; Ok(match token.variant() { Type::Absolute => Absolute(Number::parse(p, stream)?), Type::Immediate => { let number = Number::parse(p, stream)?; match number.into() { 0 => Zero, 1 => One, n => Err(Error::FatSecondaryImmediate(n as isize).context(stream.context()))?, } } _ => unreachable!("Token {token:?} passed expectation but failed match!"), }) } } impl Display for SecondaryOperand { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Direct(r) => write!(f, "{r}"), Self::Indexed(r, idx) => write!(f, "{idx}({r})"), Self::Absolute(n) => write!(f, "&{n}"), Self::Zero => write!(f, "#0"), Self::One => write!(f, "#1"), } } }