summary refs log tree commit diff
path: root/src/executor.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/executor.rs125
1 files changed, 64 insertions, 61 deletions
diff --git a/src/executor.rs b/src/executor.rs
index 24b2f47..eddf443 100644
--- a/src/executor.rs
+++ b/src/executor.rs
@@ -1,9 +1,10 @@
 //! Executor implementation for Brainfuck.
 
 use miette::Diagnostic;
+use num_traits::{One, WrappingAdd, WrappingSub, Zero};
 use thiserror::Error;
 
-use crate::{constants::TapeInner, engine::Engine, parser::Instruction};
+use crate::{engine::Engine, parser::Instruction};
 
 /// Runtime errors that can occur in brainfuck executor.
 #[derive(Debug, Diagnostic, Error)]
@@ -18,74 +19,76 @@ pub enum Error {
 	ReadInput(#[from] std::io::Error),
 }
 
-/// Struct for executor implementation, allows Engine to be implemented.
+/// Struct for executor implementation, allows u8 Engine to be implemented.
 #[derive(Clone, Copy, Debug)]
-pub struct Executor;
+pub struct U8;
 
-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;
+/// Struct for executor implementation, allows u16 Engine to be implemented.
+#[derive(Clone, Copy, Debug)]
+pub struct U16;
 
-					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,
-					};
+/// 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<E: Engine>(
+	instructions: &[Instruction],
+	tape: &mut [E::TapeInner],
+	data_pointer: &mut usize,
+) -> Result<(), Error> {
+	for instruction in instructions {
+		match *instruction {
+			Instruction::IncrementPointer => {
+				let tape_len: usize = tape.len() - 1;
+
+				if *data_pointer == tape_len {
+					*data_pointer = 0;
+				} else {
+					*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,
+			}
+			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.wrapping_add(&E::TapeInner::one()),
+				None => return Err(Error::IndexOutOfBounds(*data_pointer)),
+			},
+			Instruction::DecrementByte => match tape.get_mut(*data_pointer) {
+				Some(value) => *value = value.wrapping_sub(&E::TapeInner::one()),
+				None => return Err(Error::IndexOutOfBounds(*data_pointer)),
+			},
+			Instruction::OutputByte => {
+				E::write_byte(match tape.get(*data_pointer) {
+					Some(value) => *value,
 					None => return Err(Error::IndexOutOfBounds(*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()?;
+				})?;
+			}
+			Instruction::InputByte => {
+				let input = E::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)?;
-					}
+				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)),
+				} != &E::TapeInner::zero()
+				{
+					execute::<E>(instructions, tape, data_pointer)?;
 				}
 			}
 		}
-
-		Ok(())
 	}
+
+	Ok(())
 }