2023-08-19 23:02:24 -05:00
|
|
|
// © 2023 John Breaux
|
2023-08-25 03:05:42 -05:00
|
|
|
//! A [`JumpTarget`] contains the [pc-relative offset](Number) or [label](Identifier)
|
2023-08-23 00:13:52 -05:00
|
|
|
//! for a [Jump](Encoding::Jump) [instruction]
|
2023-08-19 23:02:24 -05:00
|
|
|
use super::*;
|
|
|
|
|
2023-08-23 00:13:52 -05:00
|
|
|
/// Contains the [pc-relative offset](Number) or [label](Identifier)
|
2023-08-23 02:25:43 -05:00
|
|
|
/// for a [Jump](Encoding::Jump) [Instruction]
|
2023-08-23 00:13:52 -05:00
|
|
|
// TODO: Allow identifiers in JumpTarget
|
2023-08-19 23:02:24 -05:00
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
|
|
pub struct JumpTarget(Number);
|
|
|
|
|
|
|
|
impl JumpTarget {
|
|
|
|
pub fn word(&self) -> u16 { u16::from(self.0) & 0x3ff }
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Parsable for JumpTarget {
|
|
|
|
/// - Identifier
|
|
|
|
/// - Number
|
|
|
|
/// - Negative
|
|
|
|
/// - Number
|
|
|
|
fn parse<'text, T>(p: &Parser, stream: &mut T) -> Result<Self, Error>
|
|
|
|
where T: crate::TokenStream<'text> {
|
|
|
|
// Try to parse a number
|
|
|
|
let target = Number::parse(p, stream)?;
|
|
|
|
match target.into() {
|
|
|
|
i if i % 2 != 0 => Err(Error::JumpedOdd(i).context(stream.context()))?,
|
|
|
|
i if (-1024..=1022).contains(&(i - 2)) => Ok(Self((target - 2) >> 1)),
|
|
|
|
i => Err(Error::JumpedTooFar(i).context(stream.context()))?,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<JumpTarget> for u16 {
|
|
|
|
fn from(value: JumpTarget) -> Self { value.0.into() }
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for JumpTarget {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
write!(f, "{}", (1 + isize::from(self.0)) << 1)
|
|
|
|
}
|
|
|
|
}
|