robson_compiler 0.1.4

Dependency of the robson cli
Documentation
use std::{
  error::Error,
  fmt::Display,
  num::{ParseFloatError, ParseIntError},
  ops::{Deref, DerefMut},
};

#[derive(Debug)]
pub struct IError {
  error: String,
}
impl IError {
  pub fn message<T>(error: T) -> Self
  where
    T: ToString,
  {
    Self {
      error: error.to_string(),
    }
  }
}
impl From<ParseIntError> for IError {
  fn from(err: ParseIntError) -> Self {
    Self {
      error: format!("{err}"),
    }
  }
}
impl From<ParseFloatError> for IError {
  fn from(err: ParseFloatError) -> Self {
    Self {
      error: format!("{err}"),
    }
  }
}
impl From<std::io::Error> for IError {
  fn from(err: std::io::Error) -> Self {
    Self {
      error: format!("{err}"),
    }
  }
}
impl Display for IError {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    write!(f, "{}", self.error)
  }
}
impl Error for IError {}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub struct TypedByte {
  pub value: [u8; 4],
  pub r#type: Type,
}
impl From<u32> for TypedByte {
  fn from(value: u32) -> Self {
    Self {
      value: value.to_be_bytes(),
      r#type: Type::Usigned,
    }
  }
}
impl From<i32> for TypedByte {
  fn from(value: i32) -> Self {
    Self {
      value: value.to_be_bytes(),
      r#type: Type::Signed,
    }
  }
}
impl From<f32> for TypedByte {
  fn from(value: f32) -> Self {
    Self {
      value: value.to_be_bytes(),
      r#type: Type::Floating,
    }
  }
}

impl Into<u32> for TypedByte {
  fn into(self) -> u32 {
    match self.r#type {
      Type::Usigned => u32::from_be_bytes(self.value),
      Type::Signed => i32::from_be_bytes(self.value) as u32,
      Type::Floating => f32::from_be_bytes(self.value) as u32,
    }
  }
}
impl Into<i32> for TypedByte {
  fn into(self) -> i32 {
    match self.r#type {
      Type::Usigned => u32::from_be_bytes(self.value) as i32,
      Type::Signed => i32::from_be_bytes(self.value),
      Type::Floating => f32::from_be_bytes(self.value) as i32,
    }
  }
}
impl Into<f32> for TypedByte {
  fn into(self) -> f32 {
    match self.r#type {
      Type::Usigned => u32::from_be_bytes(self.value) as f32,
      Type::Signed => i32::from_be_bytes(self.value) as f32,
      Type::Floating => f32::from_be_bytes(self.value),
    }
  }
}
impl Into<bool> for TypedByte {
  fn into(self) -> bool {
    match self.r#type {
      Type::Usigned => u32::from_be_bytes(self.value) != 0,
      Type::Signed => i32::from_be_bytes(self.value) != 0,
      Type::Floating => f32::from_be_bytes(self.value) != 0.0,
    }
  }
}

impl Deref for TypedByte {
  type Target = [u8; 4];
  fn deref(&self) -> &Self::Target {
    &self.value
  }
}
impl Display for TypedByte {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    write!(
      f,
      "{}",
      match self.r#type {
        Type::Usigned =>
          format!("{}", u32::from_be_bytes(self.value)),
        Type::Signed =>
          format!("i{}", i32::from_be_bytes(self.value)),
        Type::Floating =>
          format!("f{}", f32::from_be_bytes(self.value)),
      }
    )
  }
}

impl TypedByte {
  pub fn force_u32(
    &self,
    current_command: usize,
  ) -> Result<u32, IError> {
    if self.r#type != Type::Usigned {
      return Err(IError::message(format!(
        "Invalid number type at the command {current_command}"
      )));
    }
    Ok(u32::from_be_bytes(self.value))
  }
  pub fn convert(self, to_convert: Type) -> TypedByte {
    match to_convert {
      Type::Usigned => match self.r#type {
        Type::Floating => {
          (f32::from_be_bytes(self.value) as u32).into()
        }
        Type::Signed => {
          (i32::from_be_bytes(self.value) as u32).into()
        }
        Type::Usigned => self,
      },
      Type::Signed => match self.r#type {
        Type::Floating => {
          (f32::from_be_bytes(self.value) as i32).into()
        }
        Type::Signed => self,
        Type::Usigned => {
          (u32::from_be_bytes(self.value) as i32).into()
        }
      },
      Type::Floating => match self.r#type {
        Type::Floating => self,
        Type::Signed => {
          (i32::from_be_bytes(self.value) as f32).into()
        }
        Type::Usigned => {
          (u32::from_be_bytes(self.value) as f32).into()
        }
      },
    }
  }
}

#[derive(Default, Debug)]
pub struct Stack {
  pub vec: Vec<TypedByte>,
}
impl Display for Stack {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    let mut string = String::new();
    for i in &self.vec {
      string.push_str(&format!("{i}, "));
    }
    write!(f, "[{}]", string)
  }
}
impl Deref for Stack {
  type Target = Vec<TypedByte>;
  fn deref(&self) -> &Self::Target {
    &self.vec
  }
}
impl DerefMut for Stack {
  fn deref_mut(&mut self) -> &mut Self::Target {
    &mut self.vec
  }
}
impl Stack {
  pub fn top(&self) -> Result<TypedByte, IError> {
    if !self.vec.is_empty() {
      return Ok(self.vec[self.len() - 1]);
    }
    Err(IError::message(
      "Trying to access the stack while it is empty",
    ))
  }
}

const TYPES: [Type; 3] =
  [Type::Usigned, Type::Signed, Type::Floating];

#[derive(Clone, Copy, PartialEq, Debug, Eq, PartialOrd)]
pub enum Type {
  Usigned = 0,
  Signed = 1,
  Floating = 2,
}

impl From<usize> for Type {
  fn from(value: usize) -> Self {
    TYPES[value]
  }
}
impl Default for Type {
  fn default() -> Self {
    Self::Usigned
  }
}