summary refs log tree commit diff
path: root/src/executor.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/executor.rs124
1 files changed, 63 insertions, 61 deletions
diff --git a/src/executor.rs b/src/executor.rs
index f368ea9..24b2f47 100644
--- a/src/executor.rs
+++ b/src/executor.rs
@@ -1,11 +1,9 @@
 //! Executor implementation for Brainfuck.
 
-use std::io::Read;
-
 use miette::Diagnostic;
 use thiserror::Error;
 
-use crate::{constants::TapeInner, parser::Instruction};
+use crate::{constants::TapeInner, engine::Engine, parser::Instruction};
 
 /// Runtime errors that can occur in brainfuck executor.
 #[derive(Debug, Diagnostic, Error)]
@@ -20,70 +18,74 @@ pub enum Error {
 	ReadInput(#[from] std::io::Error),
 }
 
-/// Executes the provided instruction set, utilising the provided tape..
-///
-/// # Errors
-///
-/// This function will return an error if the Brainfuck code indexes out of
-/// bounds of the tape, or if the executor cannot read an input byte from stdin.
-pub fn execute(
-	instructions: &[Instruction],
-	tape: &mut [TapeInner],
-	data_pointer: &mut usize,
-) -> Result<(), Error> {
-	for instruction in instructions {
-		match *instruction {
-			Instruction::IncrementPointer => {
-				let tape_len: usize = tape.len() - 1;
+/// Struct for executor implementation, allows Engine to be implemented.
+#[derive(Clone, Copy, Debug)]
+pub struct Executor;
 
-				if *data_pointer == tape_len {
-					*data_pointer = 0;
-				} else {
-					*data_pointer += 1;
-				}
-			}
-			Instruction::DecrementPointer => {
-				*data_pointer = match *data_pointer {
-					0 => tape.len() - 1,
-					_ => *data_pointer - 1,
-				};
-			}
-			Instruction::IncrementByte => match tape.get_mut(*data_pointer) {
-				Some(value) => *value = value.overflowing_add(1).0,
-				None => return Err(Error::IndexOutOfBounds(*data_pointer)),
-			},
-			Instruction::DecrementByte => match tape.get_mut(*data_pointer) {
-				Some(value) => *value = value.overflowing_sub(1).0,
-				None => return Err(Error::IndexOutOfBounds(*data_pointer)),
-			},
-			Instruction::OutputByte => print!(
-				"{}",
-				char::from(match tape.get(*data_pointer) {
-					Some(value) => *value,
-					None => return Err(Error::IndexOutOfBounds(*data_pointer)),
-				})
-			),
-			Instruction::InputByte => {
-				let mut input: [TapeInner; 1] = [0; 1];
-
-				std::io::stdin().read_exact(&mut input)?;
+impl Executor {
+	/// Executes the provided instruction set, utilising the provided tape..
+	///
+	/// # Errors
+	///
+	/// This function will return an error if the Brainfuck code indexes out of
+	/// bounds of the tape, or if the executor cannot read an input byte from
+	/// stdin.
+	pub fn execute(
+		instructions: &[Instruction],
+		tape: &mut [TapeInner],
+		data_pointer: &mut usize,
+	) -> Result<(), Error> {
+		for instruction in instructions {
+			match *instruction {
+				Instruction::IncrementPointer => {
+					let tape_len: usize = tape.len() - 1;
 
-				match tape.get_mut(*data_pointer) {
-					Some(value) => *value = input[0],
+					if *data_pointer == tape_len {
+						*data_pointer = 0;
+					} else {
+						*data_pointer += 1;
+					}
+				}
+				Instruction::DecrementPointer => {
+					*data_pointer = match *data_pointer {
+						0 => tape.len() - 1,
+						_ => *data_pointer - 1,
+					};
+				}
+				Instruction::IncrementByte => match tape.get_mut(*data_pointer) {
+					Some(value) => *value = value.overflowing_add(1).0,
 					None => return Err(Error::IndexOutOfBounds(*data_pointer)),
-				};
-			}
-			Instruction::Loop(ref instructions) => {
-				while match tape.get(*data_pointer) {
-					Some(value) => *value,
+				},
+				Instruction::DecrementByte => match tape.get_mut(*data_pointer) {
+					Some(value) => *value = value.overflowing_sub(1).0,
 					None => return Err(Error::IndexOutOfBounds(*data_pointer)),
-				} != 0
-				{
-					execute(instructions, tape, data_pointer)?;
+				},
+				Instruction::OutputByte => {
+					Self::write_byte(match tape.get(*data_pointer) {
+						Some(value) => *value,
+						None => return Err(Error::IndexOutOfBounds(*data_pointer)),
+					})?;
+				}
+				Instruction::InputByte => {
+					let input = Self::read_byte()?;
+
+					match tape.get_mut(*data_pointer) {
+						Some(value) => *value = input,
+						None => return Err(Error::IndexOutOfBounds(*data_pointer)),
+					};
+				}
+				Instruction::Loop(ref instructions) => {
+					while match tape.get(*data_pointer) {
+						Some(value) => *value,
+						None => return Err(Error::IndexOutOfBounds(*data_pointer)),
+					} != 0
+					{
+						Self::execute(instructions, tape, data_pointer)?;
+					}
 				}
 			}
 		}
-	}
 
-	Ok(())
+		Ok(())
+	}
 }