#[derive(Debug)]
pub enum Error {
MismatchedBrackets,
IOError(std::io::Error),
EOF,
}
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Error {
Error::IOError(err)
}
}
type CellContent = u8;
struct Tape {
contents: [CellContent; 30000],
}
impl Tape {
pub fn get_cell(&self, index: usize) -> CellContent {
self.contents[index]
}
pub fn set_cell(&mut self, index: usize, value: CellContent) {
self.contents[index] = value;
}
pub fn increment(&mut self, index: usize) {
if self.contents[index] == 255 {
self.contents[index] = 0;
} else {
self.contents[index] += 1;
}
}
pub fn decrement(&mut self, index: usize) {
if self.contents[index] == 0 {
self.contents[index] = 255;
} else {
self.contents[index] -= 1;
}
}
pub fn new() -> Tape {
Tape {
contents: [0; 30000],
}
}
}
struct State<'s, R: std::io::Read + 's, W: std::io::Write + 's> {
tape: Tape,
source: Vec<char>,
instruction_index: usize,
data_index: usize,
input: &'s mut R,
output: &'s mut W,
small_buffer: [u8; 1],
}
impl<'s, R: std::io::Read, W: std::io::Write> State<'s, R, W> {
fn run_single(&mut self) -> Result<bool, Error> {
match self.source.get(self.instruction_index) {
Some(chr) => {
let result: Result<bool, Error> = match *chr {
'.' => {
self.output
.write_all(&[self.tape.get_cell(self.data_index)])?;
Ok(true)
}
',' => {
let count = self.input.read(&mut self.small_buffer)?;
if count < 1 {
return Err(Error::EOF);
}
self.tape.set_cell(self.data_index, self.small_buffer[0]);
Ok(true)
}
'+' => {
self.tape.increment(self.data_index);
Ok(true)
}
'-' => {
self.tape.decrement(self.data_index);
Ok(true)
}
'<' => {
self.data_index -= 1;
Ok(true)
}
'>' => {
self.data_index += 1;
Ok(true)
}
'[' => {
if self.tape.get_cell(self.data_index) > 0 {
Ok(true)
} else {
let mut nested = 1;
loop {
self.instruction_index += 1;
let chr = match self.source.get(self.instruction_index) {
Some(x) => Ok(x),
None => Err(Error::EOF),
}?;
if *chr == ']' {
nested -= 1;
if nested < 1 {
break;
}
}
if *chr == '[' {
nested += 1;
}
}
Ok(true)
}
}
']' => {
if self.tape.get_cell(self.data_index) == 0 {
Ok(true)
} else {
let mut nested = 1;
loop {
if self.instruction_index < 1 {
return Err(Error::MismatchedBrackets);
}
self.instruction_index -= 1;
let chr = self.source[self.instruction_index];
if chr == '[' {
nested -= 1;
if nested < 1 {
break;
}
}
if chr == ']' {
nested += 1;
}
}
Ok(true)
}
}
_ => Ok(true),
};
if result? {
self.instruction_index += 1;
}
Ok(true)
}
None => Ok(false),
}
}
pub fn execute(&mut self) -> Result<(), Error> {
loop {
if !self.run_single()? {
break;
}
}
self.output.flush()?;
Ok(())
}
pub fn new<'a>(src: &str, input: &'a mut R, output: &'a mut W) -> State<'a, R, W> {
State {
tape: Tape::new(),
source: src.chars().collect(),
instruction_index: 0,
data_index: 0,
input,
output,
small_buffer: [0; 1],
}
}
}
pub fn execute<R: std::io::Read, W: std::io::Write>(
source: &str,
input: &mut R,
output: &mut W,
) -> Result<(), Error> {
let mut state = State::new(source, input, output);
state.execute()
}