diff options
| author | Sophie Forrest <git@sophieforrest.com> | 2024-08-30 23:35:45 +1200 |
|---|---|---|
| committer | Sophie Forrest <git@sophieforrest.com> | 2024-08-30 23:35:45 +1200 |
| commit | f5f789540ad7d3f7f4f855c9db69d65cfc190ee0 (patch) | |
| tree | f532988e9a35a0d2c58efbad9daf6e66288f4a1f /src/executor.rs | |
| parent | c9ab8d38765c7c80f2ea9083ce8d326f407110ac (diff) | |
feat(engine): allow choosing engine per executor call
Diffstat (limited to 'src/executor.rs')
| -rw-r--r-- | src/executor.rs | 125 |
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(()) } |