bfy/src/bf_interpreter/interpreter.rs

188 lines
5.9 KiB
Rust
Raw Normal View History

2022-10-07 19:54:49 +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::usize;
2022-10-07 18:17:21 +00:00
2022-10-07 19:54:49 +00:00
pub struct Interpreter {
pub cells: Vec<u8>,
2022-10-07 19:54:49 +00:00
pub pointer: usize,
pub array_size: usize,
pub bf_code: String,
brackets: Vec<BfCommand>,
2022-10-07 19:54:49 +00:00
pub features: Vec<arguments::Feature>,
}
2022-10-07 19:54:49 +00:00
impl Interpreter {
2022-10-07 23:06:35 +00:00
pub fn new(
array_size: usize,
bf_code: Option<String>,
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,
array_size,
bf_code: bf_code.unwrap_or_else(|| String::new()),
brackets: Vec::new(),
features,
}
}
2022-10-07 23:05:21 +00:00
pub fn run(&mut self, bf_code: Option<String>) -> Result<i32, InterpreterError> {
let bf_code = match bf_code {
Some(bf_code) => {
self.bf_code.push_str(&*bf_code);
bf_code
}
2022-10-07 23:06:35 +00:00
None => self.bf_code.clone(),
};
2022-10-07 19:54:49 +00:00
match self.run_brainfuck_code(&bf_code) {
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-07 23:05:21 +00:00
fn iterate(&mut self, code: String) -> Result<(), InterpreterError> {
while self.cells[self.pointer] != 0 {
self.run_brainfuck_code(&code)?;
}
Ok(())
}
2022-10-07 23:11:22 +00:00
fn run_brainfuck_code(&mut self, bf_code: &str) -> Result<(), InterpreterError> {
for (i, ch) in bf_code.chars().enumerate() {
2022-10-07 19:54:49 +00:00
match BfCommand::from_char(ch, i) {
Some(cmd) => {
trace!("Executing command: {:?}", cmd);
self.execute(cmd)?
}
None => {
trace!("Skipping character: {}", ch);
}
}
}
Ok(())
}
2022-10-07 23:11:22 +00:00
fn execute(&mut self, cmd: BfCommand) -> Result<(), InterpreterError> {
match cmd {
BfCommand::IncPtr => {
self.pointer += 1;
if self.pointer >= self.array_size {
if self.features.contains(&arguments::Feature::ReversePointer) {
self.pointer = 0;
} else {
2022-10-08 10:01:28 +00:00
return Err(InterpreterErrorKind::PointerOutOfBounds(self.pointer).to_error())
}
}
}
BfCommand::DecPtr => {
if self.pointer == 0 {
if self.features.contains(&arguments::Feature::ReversePointer) {
self.pointer = self.array_size - 1;
} else {
2022-10-08 10:01:28 +00:00
return Err(InterpreterErrorKind::PointerOutOfBounds(self.pointer).to_error());
}
} else {
self.pointer -= 1;
}
2022-10-07 23:06:35 +00:00
}
BfCommand::IncVal => {
2022-10-08 10:01:28 +00:00
if self.cells[self.pointer] == 255 {
if self.features.contains(&arguments::Feature::ReverseValue) {
self.cells[self.pointer] = 0;
} else {
return Err(InterpreterErrorKind::ValueOutOfBounds.to_error());
}
} else {
self.cells[self.pointer] += 1;
}
2022-10-07 23:06:35 +00:00
}
BfCommand::DecVal => {
2022-10-08 10:01:28 +00:00
if self.cells[self.pointer] == 0 {
if self.features.contains(&arguments::Feature::ReverseValue) {
self.cells[self.pointer] = 255;
} else {
return Err(InterpreterErrorKind::ValueOutOfBounds.to_error());
}
} else {
self.cells[self.pointer] -= 1;
}
2022-10-07 23:06:35 +00:00
}
BfCommand::Print => {
print!("{}", self.cells[self.pointer] as char);
std::io::stdout().flush().unwrap();
2022-10-07 23:06:35 +00:00
}
BfCommand::Read => {
2022-10-07 22:28:14 +00:00
self.cells[self.pointer] = match std::io::stdin().bytes().next() {
Some(Ok(byte)) => byte,
Some(Err(e)) => {
2022-10-08 10:01:28 +00:00
return Err(InterpreterErrorKind::ByteReadError(e).to_error());
2022-10-07 22:28:14 +00:00
}
None => {
2022-10-08 10:01:28 +00:00
return Err(InterpreterErrorKind::ReadError.to_error());
2022-10-07 22:28:14 +00:00
}
};
2022-10-07 23:06:35 +00:00
}
BfCommand::LoopStart(i) => {
self.brackets.push(BfCommand::LoopStart(i));
2022-10-07 23:06:35 +00:00
}
BfCommand::LoopEnd(i) => {
let open_bracket = self.brackets.pop();
match open_bracket {
Some(BfCommand::LoopStart(j)) => {
if self.cells[self.pointer] != 0 {
let code = self.bf_code[j..i].to_string();
self.iterate(code)?;
2022-10-07 19:54:49 +00:00
}
2022-10-07 23:06:35 +00:00
}
_ => {
2022-10-07 23:11:22 +00:00
return Err(InterpreterError::new(
2022-10-07 23:05:21 +00:00
format!("Unmatched closing bracket at position {}", i),
2022-10-08 10:01:28 +00:00
15,
2022-10-07 23:05:21 +00:00
));
2022-10-07 19:54:49 +00:00
}
}
2022-10-07 19:54:49 +00:00
}
}
Ok(())
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.array_size];
self.pointer = 0;
self.brackets = Vec::new();
}
2022-10-07 19:54:49 +00:00
}
#[derive(Debug, PartialEq)]
enum BfCommand {
IncPtr,
DecPtr,
IncVal,
DecVal,
Print,
Read,
LoopStart(usize),
LoopEnd(usize),
2022-10-07 19:54:49 +00:00
}
impl BfCommand {
fn from_char(c: char, index: usize) -> Option<BfCommand> {
match c {
'>' => Some(BfCommand::IncPtr),
'<' => Some(BfCommand::DecPtr),
'+' => Some(BfCommand::IncVal),
'-' => Some(BfCommand::DecVal),
'.' => Some(BfCommand::Print),
',' => Some(BfCommand::Read),
'[' => Some(BfCommand::LoopStart(index)),
']' => Some(BfCommand::LoopEnd(index)),
2022-10-07 19:54:49 +00:00
_ => None,
}
}
}