brainfrsck/
interpreter.rs

1
2//! The interpreter itself and others relating to it
3
4use crate::{
5    error::{ BrainfuckError, },
6    instruction::{ Instruction },
7    components::{ Tape, Memory, IO, },
8};
9use std::{
10    iter::FromIterator,
11    fmt::{ self, Debug, Display },
12};
13
14
15/// The main 'interpreter' structure.
16/// Handles interactions between the tape, memory, and IO
17pub struct Interpreter {
18    // Instructions and instruction pointer
19    tape: Tape,
20
21    // Logical memory and data pointer
22    memory: Memory,
23
24    // Input / Output
25    io: IO,
26} impl Interpreter {
27
28    pub fn new(tape: Tape, input: Option<Vec<u8>>) -> Self {
29        let io = if input.is_some() { IO::new(input.unwrap()) } else { IO::default() };
30        Interpreter {
31            tape,
32            memory: Memory::new(),
33            io,
34        }
35    }
36
37    /// Gets the current instruction, advances the instruction pointer, handles the instructions
38    fn step(&mut self) -> Result<Option<Vec<u8>>, BrainfuckError> {
39
40        match self.tape.get_instruction() {
41            Instruction::IncPtr => {
42                self.memory.inc_ptr()?;
43            },
44            Instruction::DecPtr => {
45                self.memory.dec_ptr();
46            },
47            Instruction::IncVal => {
48                self.memory.inc_val();
49            },
50            Instruction::DecVal => {
51                self.memory.dec_val();
52            },
53            Instruction::Input => {
54                self.io.write_to(&mut self.memory);
55            },
56            Instruction::Output => {
57                self.io.pull_from(&mut self.memory);
58            },
59            Instruction::SetJump => {
60                if self.memory.pull() == 0 {
61                    self.tape.jump_forward()?;
62                }
63            },
64            Instruction::Jump => {
65                if self.memory.pull() != 0 {
66                    self.tape.jump_back()?;
67                }
68            },
69            Instruction::EOF => {
70                return Ok(Some(self.io.output()))
71            },
72            Instruction::NOP => {
73                return Ok(None)
74            },
75            Instruction::Debug => {
76                eprintln!("{:?};\n{:?};\n{:?};", self.memory, self.io, self.tape)
77            }
78        };
79        Ok(None)
80    }
81
82    /// Evaluates the code the interpreter was given and outputs the result
83    pub fn eval(&mut self) -> Result<InterpreterOutput, BrainfuckError> {
84        loop {
85            match self.step() {
86                Err(e) => return Err(e),
87                Ok(Some(output)) => return Ok(InterpreterOutput(output)),
88                Ok(None) => (),
89            }
90        }
91    }
92}
93
94/// The output type of the brainfuck interpreter
95pub struct InterpreterOutput(Vec<u8>);
96impl InterpreterOutput {
97    /// Output the data as a `String`
98    pub fn to_string(&self) -> String {
99        String::from_iter(self.0.iter().map(|byte| *byte as char))
100    }
101
102    /// Output the data as a `Vec<u8>`
103    pub fn to_vec(&self) -> Vec<u8> {
104        self.0.clone()
105    }
106}
107/// format the data as a `Vec<u8>`
108impl Debug for InterpreterOutput {
109    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
110        write!(f, "{:?}", self.0)
111    }
112} 
113/// format the data as a `String`
114impl Display for InterpreterOutput {
115    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
116        write!(f, "{}", self.to_string())
117    }
118}
119
120/// Evaluate brainfuck code with an optional input
121pub fn eval_string(code: &'static str, input: Option<Vec<u8>>) -> Result<InterpreterOutput, BrainfuckError> {
122    Interpreter::new(Tape::from_string(code), input).eval()
123}