bfy/src/bf_interpreter/interpreter.rs

392 lines
11 KiB
Rust
Raw Normal View History

2022-10-10 20:55:50 +00:00
use crate::arguments;
2022-10-08 10:01:28 +00:00
use crate::bf_interpreter::error::{InterpreterError, InterpreterErrorKind};
2022-10-07 23:06:35 +00:00
use std::io::{Read, Write};
use std::{char, usize, vec};
2022-10-07 18:17:21 +00:00
2022-10-12 11:50:22 +00:00
pub struct Interpreter<'a> {
pub cells: Vec<u8>,
2022-10-07 19:54:49 +00:00
pub pointer: usize,
2022-10-10 20:55:50 +00:00
pub bf_commands: Vec<BfCommand>,
brackets: Vec<BfCommand>,
2022-10-12 11:50:22 +00:00
pub input: &'a Box<dyn Read>,
pub output: &'a Box<dyn Write>,
2022-10-07 19:54:49 +00:00
pub features: Vec<arguments::Feature>,
}
2022-10-12 11:50:22 +00:00
impl<'a> Interpreter<'a> {
2022-10-07 23:06:35 +00:00
pub fn new(
array_size: usize,
2022-10-12 11:50:22 +00:00
input: &'a mut Box<dyn Read>,
output: &'a mut Box<dyn Write>,
2022-10-07 23:06:35 +00:00
features: Vec<arguments::Feature>,
) -> Self {
2022-10-07 19:54:49 +00:00
Self {
cells: vec![0; array_size],
2022-10-07 19:54:49 +00:00
pointer: 0,
2022-10-10 20:55:50 +00:00
bf_commands: vec![],
2022-10-07 19:54:49 +00:00
brackets: Vec::new(),
2022-10-12 11:50:22 +00:00
input,
output,
2022-10-07 19:54:49 +00:00
features,
}
}
2022-10-10 20:55:50 +00:00
pub fn run(&mut self, bf_code: String) -> Result<i32, InterpreterError> {
self.bf_commands = to_bf_commands(bf_code.chars().collect())?;
2022-10-07 19:54:49 +00:00
2022-10-10 20:55:50 +00:00
match self.run_brainfuck_code(&self.bf_commands.clone()) {
Ok(_) => Ok(0),
2022-10-07 23:06:35 +00:00
Err(e) => Err(e),
}
}
2022-10-07 19:54:49 +00:00
2022-10-10 20:55:50 +00:00
// +[>++<-]
2022-10-10 20:55:50 +00:00
fn iterate(&mut self, code: &Vec<BfCommand>) -> Result<(), InterpreterError> {
trace!("Iterate: {:?}", code);
while self.cells[self.pointer] != 0 {
2022-10-10 20:55:50 +00:00
self.run_brainfuck_code(code)?;
}
Ok(())
}
2022-10-10 20:55:50 +00:00
fn run_brainfuck_code(&mut self, bf_code: &Vec<BfCommand>) -> Result<(), InterpreterError> {
for command in bf_code {
match command {
BfCommand::IncPtr => self.increment_pointer()?,
BfCommand::DecPtr => self.decrement_pointer()?,
BfCommand::IncVal => self.increment_value()?,
BfCommand::DecVal => self.decrement_value()?,
BfCommand::Print => self.output_value()?,
BfCommand::Read => self.input_value()?,
BfCommand::Loop(loop_body) => self.iterate(loop_body)?,
}
}
2022-10-10 20:55:50 +00:00
Ok(())
}
2022-10-10 20:55:50 +00:00
fn increment_pointer(&mut self) -> Result<(), InterpreterError> {
trace!("Increment pointer");
self.pointer += 1;
if self.pointer >= self.cells.len() {
2022-10-10 20:55:50 +00:00
if self.features.contains(&arguments::Feature::ReversePointer) {
self.pointer = 0;
} else {
return Err(InterpreterErrorKind::PointerOutOfBounds(self.pointer).to_error());
2022-10-07 23:06:35 +00:00
}
2022-10-10 20:55:50 +00:00
}
Ok(())
}
fn decrement_pointer(&mut self) -> Result<(), InterpreterError> {
trace!("Decrement pointer");
if self.pointer == 0 {
if self.features.contains(&arguments::Feature::ReversePointer) {
self.pointer = self.cells.len() - 1;
2022-10-10 20:55:50 +00:00
} else {
return Err(InterpreterErrorKind::PointerOutOfBounds(self.pointer).to_error());
2022-10-07 23:06:35 +00:00
}
2022-10-10 20:55:50 +00:00
} else {
self.pointer -= 1;
}
Ok(())
}
fn increment_value(&mut self) -> Result<(), InterpreterError> {
trace!("Increment value");
if self.cells[self.pointer] == 255 {
if !self.features.contains(&arguments::Feature::NoReverseValue) {
self.cells[self.pointer] = 0;
} else {
return Err(InterpreterErrorKind::ValueOutOfBounds.to_error());
2022-10-07 23:06:35 +00:00
}
2022-10-10 20:55:50 +00:00
} else {
self.cells[self.pointer] += 1;
}
Ok(())
}
fn decrement_value(&mut self) -> Result<(), InterpreterError> {
trace!("Decrement value");
if self.cells[self.pointer] == 0 {
if !self.features.contains(&arguments::Feature::NoReverseValue) {
self.cells[self.pointer] = 255;
} else {
return Err(InterpreterErrorKind::ValueOutOfBounds.to_error());
2022-10-07 23:06:35 +00:00
}
2022-10-10 20:55:50 +00:00
} else {
self.cells[self.pointer] -= 1;
}
Ok(())
}
fn output_value(&mut self) -> Result<(), InterpreterError> {
trace!("Output value");
if self.features.contains(&arguments::Feature::AllowUtf8) {
let c = char::from_u32(self.cells[self.pointer] as u32);
match c {
Some(c) => print!("{}", c),
None => return Err(InterpreterErrorKind::InvalidUtf8.to_error()),
2022-10-07 23:06:35 +00:00
}
2022-10-10 20:55:50 +00:00
} else {
print!("{}", self.cells[self.pointer] as char);
}
match std::io::stdout().flush() {
Ok(_) => Ok(()),
Err(e) => Err(InterpreterErrorKind::FlushError(e).to_error()),
}
}
fn input_value(&mut self) -> Result<(), InterpreterError> {
trace!("Input value");
let mut input = [0; 1];
match std::io::stdin().read_exact(&mut input) {
Ok(_) => {
self.cells[self.pointer] = input[0];
Ok(())
2022-10-07 19:54:49 +00:00
}
2022-10-10 20:55:50 +00:00
Err(e) => Err(InterpreterErrorKind::IoError(e).to_error()),
2022-10-07 19:54:49 +00:00
}
}
2022-10-07 22:33:44 +00:00
pub fn reset(&mut self) {
self.cells = vec![0; self.cells.len()];
2022-10-07 22:33:44 +00:00
self.pointer = 0;
self.brackets = Vec::new();
2022-10-10 20:55:50 +00:00
self.bf_commands = Vec::new();
2022-10-07 22:33:44 +00:00
}
2022-10-07 19:54:49 +00:00
}
2022-10-10 20:55:50 +00:00
#[derive(Debug, PartialEq, Clone)]
pub enum BfCommand {
2022-10-07 19:54:49 +00:00
IncPtr,
DecPtr,
IncVal,
DecVal,
Print,
Read,
2022-10-10 20:55:50 +00:00
Loop(Vec<BfCommand>),
}
fn to_bf_commands(bf_code: Vec<char>) -> Result<Vec<BfCommand>, InterpreterError> {
let mut bf_commands = Vec::new();
let mut i = 0;
while i < bf_code.len() {
match bf_code[i] {
'[' => {
let mut bracket_count = 1;
let mut j = i + 1;
while j < bf_code.len() {
match bf_code[j] {
'[' => bracket_count += 1,
']' => bracket_count -= 1,
_ => (),
}
if bracket_count == 0 {
break;
}
j += 1;
}
if bracket_count != 0 {
return Err(InterpreterErrorKind::UnmatchedBracket.to_error());
}
bf_commands.push(BfCommand::Loop(to_bf_commands(bf_code[i + 1..j].to_vec())?));
i = j;
}
_ => {
match BfCommand::from(bf_code[i]) {
Some(command) => bf_commands.push(command),
None => (),
}
},
}
i += 1;
}
Ok(bf_commands)
2022-10-07 19:54:49 +00:00
}
impl BfCommand {
2022-10-10 20:55:50 +00:00
fn from(c: char) -> Option<Self> {
2022-10-07 19:54:49 +00:00
match c {
'>' => Some(BfCommand::IncPtr),
'<' => Some(BfCommand::DecPtr),
'+' => Some(BfCommand::IncVal),
'-' => Some(BfCommand::DecVal),
'.' => Some(BfCommand::Print),
',' => Some(BfCommand::Read),
_ => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
2022-10-10 20:55:50 +00:00
use pretty_assertions::assert_eq; // for testing only
use crate::utils;
#[test]
fn print_h_combine_repl() {
let mut interpreter = Interpreter::new(
30000,
vec![],
);
2022-10-10 20:55:50 +00:00
assert_eq!(interpreter.run(String::from(">+++++++++[<++++ ++++>-]<.")), Ok(0));
2022-10-10 20:55:50 +00:00
println!();
}
2022-10-10 20:55:50 +00:00
#[test]
fn print_h_repl() {
let mut interpreter = Interpreter::new(
30000,
vec![],
);
2022-10-10 20:55:50 +00:00
assert_eq!(interpreter.run(String::from(">+++++++++")), Ok(0));
assert_eq!(interpreter.run(String::from("[<++++ ++++>-]<.")), Ok(0));
2022-10-10 20:55:50 +00:00
println!();
}
2022-10-10 20:55:50 +00:00
#[test]
fn nested_loop_level_1_combine() {
let mut interpreter = Interpreter::new(
5,
vec![],
);
assert_eq!(interpreter.run(String::from("++[>++[>+<-]<-]")), Ok(0));
assert_eq!(interpreter.cells[2], 4);
println!();
}
#[test]
fn execute_hello_world_from_file() {
let mut interpreter = Interpreter::new(
30000,
vec![],
);
2022-10-10 20:55:50 +00:00
println!();
assert_eq!(interpreter.run(
utils::read_brainfuck_code(
&String::from("test_code/hello_world.bf"))), Ok(0));
}
#[test]
fn execute_print_hi_from_file() {
let mut interpreter = Interpreter::new(
30000,
vec![],
);
2022-10-10 20:55:50 +00:00
println!();
assert_eq!(interpreter.run(
utils::read_brainfuck_code(&String::from("test_code/print_hi.bf"))), Ok(0));
}
#[test]
fn execute_print_hi_yooo_from_file() {
let mut interpreter = Interpreter::new(
30000,
vec![],
);
2022-10-10 20:55:50 +00:00
println!();
assert_eq!(interpreter.run(
utils::read_brainfuck_code(&String::from("test_code/print_hi_yooo.bf"))),
Ok(0));
}
#[test]
fn execute_print_my_first_name_from_formatted_file() {
let mut interpreter = Interpreter::new(
30000,
vec![],
);
println!();
assert_eq!(interpreter.run(
utils::read_brainfuck_code(&String::from("test_code/print_my_first_name_formatted.bf"))),
Ok(0));
}
#[test]
fn execute_print_my_first_name_from_file() {
let mut interpreter = Interpreter::new(
30000,
vec![],
);
println!();
assert_eq!(interpreter.run(
utils::read_brainfuck_code(&String::from("test_code/print_my_first_name.bf"))),
Ok(0));
}
#[test]
fn execute_print_my_first_name_and_last_name_from_formatted_file() {
let mut interpreter = Interpreter::new(
30000,
vec![],
);
println!();
assert_eq!(interpreter.run(
utils::read_brainfuck_code(
&String::from("test_code/print_my_first_name_and_last_name_formatted.bf"))),
Ok(0));
}
#[test]
fn execute_print_my_first_name_and_last_name_from_file() {
let mut interpreter = Interpreter::new(
30000,
vec![],
);
println!();
assert_eq!(interpreter.run(utils::read_brainfuck_code(
&String::from("test_code/print_my_first_name_and_last_name.bf"))),
Ok(0));
}
#[test]
fn reset() {
let mut interpreter = Interpreter::new(
30000,
vec![],
);
2022-10-10 20:55:50 +00:00
assert_eq!(interpreter.run(String::from(">++++")), Ok(0));
assert_eq!(interpreter.pointer, 1);
assert_eq!(interpreter.cells[0], 0);
assert_eq!(interpreter.cells[1], 4);
2022-10-10 20:55:50 +00:00
// assert_eq!(interpreter.commands, vec!['>', '+', '+', '+', '+']);
// reset
interpreter.reset();
assert_eq!(interpreter.pointer, 0);
assert_eq!(interpreter.cells[0], 0);
assert_eq!(interpreter.cells[1], 0);
2022-10-10 20:55:50 +00:00
assert_eq!(interpreter.bf_commands, Vec::<BfCommand>::new());
}
}