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 | f752160c6ebcee747a61e6febc4789d0b04ccd12 (patch) | |
| tree | 76e123279abbd1797ba281f35cbcba61136ef7bd /src/executor.rs | |
| parent | 98d7946709032aae5e1d0d35cff78efc55550900 (diff) | |
feat: implement generic engine for executor
Diffstat (limited to 'src/executor.rs')
| -rw-r--r-- | src/executor.rs | 124 |
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(()) + } } |