// © 2023 John Breaux //! A [`JumpTarget`] contains the [pc-relative offset](Number) or [label](Identifier) //! for a [Jump](Encoding::Jump) [instruction] use super::*; /// Contains the [pc-relative offset](Number) or [label](Identifier) /// for a [Jump](Encoding::Jump) [Instruction] #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum JumpTarget { Number(Number), Identifier(Identifier), } impl JumpTarget { pub fn word(&self) -> Option { match self { JumpTarget::Number(n) => Some(u16::from(*n) & 0x3ff), JumpTarget::Identifier(_) => None, } } pub fn squish(value: isize) -> Result { match value { i if i % 2 != 0 => Err(ParseError::JumpedOdd(i))?, i if (-1024..=1022).contains(&(i - 2)) => Ok(((value >> 1) - 1) as u16 & 0x3ff), i => Err(ParseError::JumpedTooFar(i))?, } } pub fn unsquish(value: u16) -> isize { (value as isize + 1) << 1 } } impl Parsable for JumpTarget { // - Identifier // - Number fn parse<'text, T>(p: &Parser, stream: &mut T) -> Result where T: crate::TokenStream<'text> { // Try to parse a number if let Some(num) = Number::try_parse(p, stream)? { Self::try_from(num) } else { // if that fails, try to parse an identifier instead Ok(Self::Identifier(Identifier::parse(p, stream)?)) } } } impl TryFrom for JumpTarget { type Error = ParseError; fn try_from(value: Number) -> Result { Ok(Self::Number(Self::squish(value.into())?.into())) } } impl Display for JumpTarget { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Number(num) => write!(f, "{:x}", Self::unsquish(u16::from(*num))), Self::Identifier(id) => write!(f, "{id}"), } } }