robson_compiler 0.1.6

Dependency of the robson cli
Documentation
use std::collections::HashMap;

use crate::{data_struct::IError, macros::ierror};

pub fn u32_add(a: [u8; 4], b: [u8; 4]) -> u32 {
  u32::from_be_bytes(a) + u32::from_be_bytes(b)
}

pub fn f32_add(a: [u8; 4], b: [u8; 4]) -> f32 {
  f32::from_be_bytes(a) + f32::from_be_bytes(b)
}

pub fn i32_add(a: [u8; 4], b: [u8; 4]) -> i32 {
  i32::from_be_bytes(a) + i32::from_be_bytes(b)
}

pub fn u32_sub(a: [u8; 4], b: [u8; 4]) -> u32 {
  u32::from_be_bytes(a) - u32::from_be_bytes(b)
}

pub fn f32_sub(a: [u8; 4], b: [u8; 4]) -> f32 {
  f32::from_be_bytes(a) - f32::from_be_bytes(b)
}

pub fn i32_sub(a: [u8; 4], b: [u8; 4]) -> i32 {
  i32::from_be_bytes(a) - i32::from_be_bytes(b)
}
pub fn u32_mul(a: [u8; 4], b: [u8; 4]) -> u32 {
  u32::from_be_bytes(a) * u32::from_be_bytes(b)
}

pub fn f32_mul(a: [u8; 4], b: [u8; 4]) -> f32 {
  f32::from_be_bytes(a) * f32::from_be_bytes(b)
}

pub fn i32_mul(a: [u8; 4], b: [u8; 4]) -> i32 {
  i32::from_be_bytes(a) * i32::from_be_bytes(b)
}

pub fn u32_div(a: [u8; 4], b: [u8; 4]) -> u32 {
  u32::from_be_bytes(a) / u32::from_be_bytes(b)
}

pub fn f32_div(a: [u8; 4], b: [u8; 4]) -> f32 {
  f32::from_be_bytes(a) / f32::from_be_bytes(b)
}

pub fn i32_div(a: [u8; 4], b: [u8; 4]) -> i32 {
  i32::from_be_bytes(a) / i32::from_be_bytes(b)
}

pub fn u32_mod(a: [u8; 4], b: [u8; 4]) -> u32 {
  u32::from_be_bytes(a) % u32::from_be_bytes(b)
}

pub fn f32_mod(a: [u8; 4], b: [u8; 4]) -> f32 {
  f32::from_be_bytes(a) % f32::from_be_bytes(b)
}

pub fn i32_mod(a: [u8; 4], b: [u8; 4]) -> i32 {
  i32::from_be_bytes(a) % i32::from_be_bytes(b)
}

pub fn approx_equal(a: f32, b: f32, decimal_places: u8) -> bool {
  let factor = 10.0f32.powi(decimal_places as i32);
  let a = (a * factor).trunc();
  let b = (b * factor).trunc();
  a == b
}
pub fn create_kind_byte(
  type1: u8,
  type2: u8,
  type3: u8,
  type4: u8,
) -> u8 {
  let mut kind_byte: u8 = 0;
  kind_byte += type1 * 64;
  kind_byte += type2 * 16;
  kind_byte += type3 * 4;
  kind_byte += type4;
  kind_byte
}
pub fn convert_kind_byte(a: u8) -> [usize; 4] {
  [
    (a >> 6) as usize,
    (((a >> 4) << 6) >> 6) as usize,
    (((a >> 2) << 6) >> 6) as usize,
    ((a << 6) >> 6) as usize,
  ]
}

pub fn create_two_bits(bits: [bool; 2]) -> u8 {
  let mut byte = 0;
  byte += bits[0] as u8;
  byte += bits[1] as u8 * 2;
  byte
}

pub fn convert_two_bits(byte: u8) -> [bool; 2] {
  [((byte << 7) >> 7) != 0, (byte >> 1) != 0]
}

pub fn convert_macro_robson(
  expr: String,
  values: &HashMap<String, String>,
  current: usize,
) -> Result<(String, bool, bool), IError> {
  let splited = expr.split(' ').collect::<Vec<&str>>();

  if splited.len() == 1 {
    return Ok((
      values
        .get(&expr)
        .ok_or(IError::message(format!("Can't find {}", expr)))?
        .to_string(),
      false,
      false,
    ));
  }
  let is_expr = true;
  if splited.len() != 2 {
    return ierror!("Failed to parse '{}'", expr);
  }
  if splited[1].contains("?ROBSON") {
    return ierror!("Cant use an expression with x?ROBSONs");
  }

  let mut value = values
    .get(splited[1])
    .ok_or(IError::message("Malformated macro param"))?
    .to_owned();
  let mut last: Option<char> = None;
  let mut has_next = false;
  let chs = splited[0].chars().collect::<Vec<char>>();

  for (i, char) in chs.iter().enumerate() {
    if let Some(l) = last {
      match l {
        's' => {
          let s = value.split(*char).collect::<Vec<&str>>();
          value = s[current].to_string();
        }
        'i' => {
          let s = value.split(*char).collect::<Vec<&str>>();
          if s.len() != 3 {
            return ierror!(
              "Invalid value inside expression '{}'",
              value
            );
          }

          value = s[1].to_string();
        }
        'c' => {
          let chars = value.chars().collect::<Vec<char>>();
          value = String::new();
          for i in chars {
            let mut bytes: [u8; 4] = [0, 0, 0, 0];

            i.encode_utf8(&mut bytes);
            let mut zeroes = 0;
            for a in bytes {
              if a == 0 {
                zeroes += 1;
              }
            }
            let prefix = match char {
              'c' => "comeu",
              'f' => "fudeu",
              _ => {
                return ierror!(
                  "Invalid complement for 'c' macro expression "
                );
              }
            };
            let number = u32::from_be_bytes(bytes) >> (8 * zeroes);
            value.push_str(&format!("{prefix} {number}\n"));
          }
        }
        _ => return ierror!("Invalid macro expression"),
      }
      last = None;
    } else {
      match char {
        'r' => {
          let chars = value.chars().collect::<Vec<char>>();
          if current >= chars.len() {
            return ierror!("Out of bounds macro expression");
          }
          if current + 1 < chars.len() {
            has_next = true;
          }
          value = chars[current].to_string();
        }
        _ => {
          if (i + 1) >= chs.len() {
            return ierror!("Incomplete '{}' macro argument", char);
          }
          last = Some(*char);
        }
      }
    }
  }

  Ok((value, has_next, is_expr))
}