291 lines
7.6 KiB
Rust
291 lines
7.6 KiB
Rust
use crate::arguments::Feature;
|
|
use crate::bf_interpreter::error::{InterpreterError, InterpreterErrorKind};
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
pub enum Cell {
|
|
Byte(u8),
|
|
Utf8(u32),
|
|
}
|
|
|
|
impl Cell {
|
|
pub fn set_value(&mut self, ch: char) {
|
|
match self {
|
|
Cell::Byte(p) => {
|
|
*p = ch as u8;
|
|
}
|
|
Cell::Utf8(p) => {
|
|
*p = ch as u32;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Cell {
|
|
pub fn default_cell(future: &Vec<Feature>) -> Self {
|
|
if future.contains(&Feature::AllowUtf8) {
|
|
Cell::Utf8(0)
|
|
} else {
|
|
Cell::Byte(0)
|
|
}
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
/// For testing purposes
|
|
pub fn new(value: u32, future: &Vec<Feature>) -> Self {
|
|
if future.contains(&Feature::AllowUtf8) {
|
|
Cell::Utf8(value)
|
|
} else {
|
|
Cell::Byte(value as u8)
|
|
}
|
|
}
|
|
|
|
pub fn get_value(&self) -> u8 {
|
|
match self {
|
|
Self::Byte(value) => *value,
|
|
Self::Utf8(value) => *value as u8,
|
|
}
|
|
}
|
|
|
|
pub fn get_value_utf8(&self) -> u32 {
|
|
match self {
|
|
Self::Byte(value) => *value as u32,
|
|
Self::Utf8(value) => *value,
|
|
}
|
|
}
|
|
|
|
pub fn increment(&mut self, no_reverse_value: bool) -> Result<(), InterpreterError> {
|
|
if self.get_value_utf8() == self.max_value() && no_reverse_value {
|
|
return Err(InterpreterErrorKind::ValueOutOfBounds.to_error());
|
|
}
|
|
match self {
|
|
Self::Byte(value) => {
|
|
if *value == 255 {
|
|
*value = 0;
|
|
} else {
|
|
*value += 1;
|
|
}
|
|
}
|
|
Self::Utf8(value) => {
|
|
if *value == 1114111 {
|
|
*value = 0;
|
|
} else {
|
|
*value += 1;
|
|
}
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub fn decrement(&mut self, no_reverse_value: bool) -> Result<(), InterpreterError> {
|
|
if self.get_value_utf8() == 0 && no_reverse_value {
|
|
return Err(InterpreterErrorKind::ValueOutOfBounds.to_error());
|
|
}
|
|
match self {
|
|
Self::Byte(value) => {
|
|
if *value == 0 {
|
|
*value = 255;
|
|
} else {
|
|
*value -= 1;
|
|
}
|
|
}
|
|
Self::Utf8(value) => {
|
|
if *value == 0 {
|
|
*value = 1114111;
|
|
} else {
|
|
*value -= 1;
|
|
}
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub fn max_value(&self) -> u32 {
|
|
match self {
|
|
Self::Byte(_) => u8::MAX as u32,
|
|
Self::Utf8(_) => 1114111,
|
|
}
|
|
}
|
|
|
|
pub fn to_char(&self) -> Result<char, InterpreterError> {
|
|
let c = match self {
|
|
Self::Byte(value) => Some(*value as char),
|
|
Self::Utf8(value) => char::from_u32(*value),
|
|
};
|
|
|
|
if let Some(c) = c {
|
|
Ok(c)
|
|
} else {
|
|
Err(InterpreterErrorKind::InvalidUtf8.to_error())
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for Cell {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
Self::Byte(value) => write!(f, "{}", value),
|
|
Self::Utf8(value) => write!(f, "{}", value),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use pretty_assertions::assert_eq;
|
|
|
|
#[test]
|
|
fn test_increment_u8_no_revers() {
|
|
let mut cell = Cell::default_cell(&vec![]);
|
|
cell.increment(true).unwrap();
|
|
assert_eq!(cell, Cell::Byte(1));
|
|
|
|
for _ in 0..254 {
|
|
cell.increment(true).unwrap();
|
|
}
|
|
assert_eq!(cell, Cell::Byte(255));
|
|
|
|
assert_eq!(
|
|
cell.increment(true).unwrap_err(),
|
|
InterpreterErrorKind::ValueOutOfBounds.to_error()
|
|
);
|
|
assert_eq!(cell, Cell::Byte(255));
|
|
}
|
|
|
|
#[test]
|
|
fn test_increment_u32_no_revers() {
|
|
let mut cell = Cell::default_cell(&vec![Feature::AllowUtf8]);
|
|
cell.increment(true).unwrap();
|
|
assert_eq!(cell, Cell::Utf8(1));
|
|
|
|
for _ in 0..1114110 {
|
|
cell.increment(true).unwrap();
|
|
}
|
|
assert_eq!(cell, Cell::Utf8(1114111));
|
|
|
|
assert_eq!(
|
|
cell.increment(true).unwrap_err(),
|
|
InterpreterErrorKind::ValueOutOfBounds.to_error()
|
|
);
|
|
assert_eq!(cell, Cell::Utf8(1114111));
|
|
}
|
|
|
|
#[test]
|
|
fn test_increment_u8_revers() {
|
|
let mut cell = Cell::default_cell(&vec![]);
|
|
cell.increment(false).unwrap();
|
|
assert_eq!(cell, Cell::Byte(1));
|
|
|
|
for _ in 0..254 {
|
|
cell.increment(false).unwrap();
|
|
}
|
|
assert_eq!(cell, Cell::Byte(255));
|
|
|
|
cell.increment(false).unwrap();
|
|
assert_eq!(cell, Cell::Byte(0));
|
|
}
|
|
|
|
#[test]
|
|
fn test_increment_u32_revers() {
|
|
let mut cell = Cell::default_cell(&vec![Feature::AllowUtf8]);
|
|
cell.increment(false).unwrap();
|
|
assert_eq!(cell, Cell::Utf8(1));
|
|
|
|
for _ in 0..1114110 {
|
|
cell.increment(false).unwrap();
|
|
}
|
|
assert_eq!(cell, Cell::Utf8(1114111));
|
|
|
|
cell.increment(false).unwrap();
|
|
assert_eq!(cell, Cell::Utf8(0));
|
|
}
|
|
|
|
#[test]
|
|
fn test_decrement_u8_no_revers() {
|
|
let mut cell = Cell::new(255, &vec![]);
|
|
cell.decrement(true).unwrap();
|
|
assert_eq!(cell, Cell::Byte(254));
|
|
|
|
for _ in 0..254 {
|
|
cell.decrement(true).unwrap();
|
|
}
|
|
assert_eq!(cell, Cell::Byte(0));
|
|
|
|
assert_eq!(
|
|
cell.decrement(true).unwrap_err(),
|
|
InterpreterErrorKind::ValueOutOfBounds.to_error()
|
|
);
|
|
assert_eq!(cell, Cell::Byte(0));
|
|
}
|
|
|
|
#[test]
|
|
fn test_decrement_u32_no_revers() {
|
|
let mut cell = Cell::new(1114111, &vec![Feature::AllowUtf8]);
|
|
cell.decrement(true).unwrap();
|
|
assert_eq!(cell, Cell::Utf8(1114110));
|
|
|
|
for _ in 0..1114110 {
|
|
cell.decrement(true).unwrap();
|
|
}
|
|
assert_eq!(cell, Cell::Utf8(0));
|
|
|
|
assert_eq!(
|
|
cell.decrement(true).unwrap_err(),
|
|
InterpreterErrorKind::ValueOutOfBounds.to_error()
|
|
);
|
|
assert_eq!(cell, Cell::Utf8(0));
|
|
}
|
|
|
|
#[test]
|
|
fn test_decrement_u8_revers() {
|
|
let mut cell = Cell::new(0, &vec![]);
|
|
cell.decrement(false).unwrap();
|
|
assert_eq!(cell, Cell::Byte(255));
|
|
|
|
for _ in 0..254 {
|
|
cell.decrement(false).unwrap();
|
|
}
|
|
assert_eq!(cell, Cell::Byte(1));
|
|
|
|
cell.decrement(false).unwrap();
|
|
assert_eq!(cell, Cell::Byte(0));
|
|
}
|
|
|
|
#[test]
|
|
fn test_decrement_u32_revers() {
|
|
let mut cell = Cell::new(0, &vec![Feature::AllowUtf8]);
|
|
cell.decrement(false).unwrap();
|
|
assert_eq!(cell, Cell::Utf8(1114111));
|
|
|
|
for _ in 0..1114110 {
|
|
cell.decrement(false).unwrap();
|
|
}
|
|
assert_eq!(cell, Cell::Utf8(1));
|
|
|
|
cell.decrement(false).unwrap();
|
|
assert_eq!(cell, Cell::Utf8(0));
|
|
}
|
|
|
|
#[test]
|
|
fn test_to_char() {
|
|
let cell = Cell::new(65, &vec![]);
|
|
assert_eq!(cell.to_char().unwrap(), 'A');
|
|
|
|
let cell = Cell::new(129408, &vec![Feature::AllowUtf8]);
|
|
assert_eq!(cell.to_char().unwrap(), '🦀');
|
|
|
|
let cell = Cell::new(129392, &vec![Feature::AllowUtf8]);
|
|
assert_eq!(cell.to_char().unwrap(), '🥰');
|
|
}
|
|
|
|
#[test]
|
|
fn test_set_value() {
|
|
let mut cell = Cell::default_cell(&vec![]);
|
|
cell.set_value('A');
|
|
assert_eq!(cell, Cell::Byte(65));
|
|
|
|
let mut cell = Cell::default_cell(&vec![Feature::AllowUtf8]);
|
|
cell.set_value('🦀');
|
|
assert_eq!(cell, Cell::Utf8(129408));
|
|
}
|
|
}
|