Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'lemu/src/memory.rs')
| -rw-r--r-- | lemu/src/memory.rs | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/lemu/src/memory.rs b/lemu/src/memory.rs new file mode 100644 index 0000000..bd9ca52 --- /dev/null +++ b/lemu/src/memory.rs @@ -0,0 +1,185 @@ +use beef::lean::Cow; + +use crate::debug::{info::VarData, printable::Printable}; +#[derive(Clone, Debug)] +pub enum LVar<'string> { + Num(f64), + String(Cow<'string, str>), +} + +impl PartialEq for LVar<'_> { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::Num(a), Self::Num(b)) => (a - b).abs() < 0.000_001, + (Self::String(l0), Self::String(r0)) => l0 == r0, + _ => false, + } + } +} + +impl Default for LVar<'static> { + fn default() -> Self { + Self::Num(0.0) + } +} + +impl LVar<'_> { + // get null + pub const fn null() -> LVar<'static> { + LVar::Num(0.0) + } + + pub const fn num(&self) -> Option<f64> { + match *self { + Self::Num(n) => Some(n), + Self::String(_) => None, + } + } + + pub const fn num_mut(&mut self) -> Option<&mut f64> { + match self { + LVar::Num(x) => Some(x), + LVar::String(_) => None, + } + } +} + +#[derive(Clone, Copy)] +pub struct LAddress { + pub address: u32, +} + +impl LAddress { + /// # Safety + /// + /// ensure that address is valid + pub(crate) const unsafe fn addr(address: u32) -> Self { + LAddress { address } + } +} + +#[derive(Copy, Clone)] +pub struct Priv { + _priv: (), +} + +impl std::fmt::Debug for LAddress { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:x}", self.address) + } +} + +impl std::fmt::Display for LVar<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Num(n) => write!(f, "{}", crate::debug::ff(*n)), // yeeeeahhhh + Self::String(s) => write!(f, r#""{s}""#), + } + } +} + +impl From<f64> for LVar<'_> { + fn from(value: f64) -> Self { + Self::Num(value) + } +} + +impl From<bool> for LVar<'_> { + fn from(value: bool) -> Self { + Self::Num(value.into()) + } +} + +impl From<usize> for LVar<'_> { + fn from(value: usize) -> Self { + Self::Num(value as f64) + } +} + +impl<'s> From<&'s str> for LVar<'s> { + fn from(value: &'s str) -> Self { + Self::String(value.into()) + } +} + +impl<'s> From<Cow<'s, str>> for LVar<'s> { + fn from(value: Cow<'s, str>) -> Self { + Self::String(value) + } +} + +#[derive(Debug)] +pub struct LRegistry<'str>(pub Box<[LVar<'str>]>); + +impl<'s> std::ops::Index<LAddress> for LRegistry<'s> { + type Output = LVar<'s>; + + fn index(&self, index: LAddress) -> &Self::Output { + debug_assert!((index.address as usize) < self.0.len()); + // SAFETY: LAddress promises to be in our bounds. + // lreg has no constructors, so unless you keep one around, grab a laddr, and use it on the old lreg, + // this is safeish. + // lreg is private to the outside world, so its ok + unsafe { self.0.get_unchecked(index.address as usize) } + } +} + +impl<'s> std::ops::IndexMut<LAddress> for LRegistry<'s> { + fn index_mut(&mut self, index: LAddress) -> &mut Self::Output { + debug_assert!((index.address as usize) < self.0.len()); + // SAFETY: see above + unsafe { self.0.get_unchecked_mut(index.address as usize) } + } +} + +impl std::fmt::Display for LRegistry<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "R[")?; + let mut iter = self + .0 + .iter() + .enumerate() + .filter(|&(_, v)| v != &LVar::null()); + if let Some((i, v)) = iter.next() { + write!(f, "{i}: {v}")?; + } + for (i, v) in iter { + write!(f, ", {i}: {v}")?; + } + write!(f, "]") + } +} + +impl LRegistry<'_> { + pub fn get(&self, a: LAddress) -> &LVar { + &self[a] + } +} + +impl Printable for LRegistry<'_> { + fn print( + &self, + info: &crate::debug::info::DebugInfo<'_>, + f: &mut impl std::fmt::Write, + ) -> std::fmt::Result { + write!(f, "R[")?; + let mut iter = self + .0 + .iter() + .zip(0..self.0.len() as u32) + .filter(|&(v, _)| v != &LVar::null()) + // SAFETY: the address comes from me + .map(|(v, i)| (&info[unsafe { LAddress::addr(i) }], v)) + .filter_map(|(d, v)| match d { + VarData::Variable(d) => Some((*d, v)), + VarData::Constant(_) => None, + }); + if let Some((i, v)) = iter.next() { + write!(f, "{i}: {v}")?; + } + for (i, v) in iter { + write!(f, ", {i}: {v}")?; + } + write!(f, "]") + } +} |