#![warn(
clippy::all,
clippy::restriction,
clippy::pedantic,
clippy::nursery,
clippy::cargo
)]
use std::io::{BufRead, Write};
use std::{io, process::exit};
fn match_right(index: usize, program: &[u8], lma: usize, lmv: usize) -> (usize, usize, usize) {
if lma == index {
return (lmv, lma, lmv);
}
let lma = index;
let mut index = index;
let mut depth = 0;
while index < program.len() {
if program[index] as char == '[' {
depth += 1;
} else if program[index] as char == ']' {
depth -= 1;
}
if depth == 0 {
break;
}
index += 1;
}
if depth != 0 {
return (0, lma, lmv);
}
(index, lma, index)
}
fn match_left(
index: usize,
program: &[u8],
lma: usize,
lmv: usize,
) -> (Option<usize>, usize, usize) {
if lma == index {
return (Some(lmv), lma, lmv);
}
let lma = index;
let origin = index;
let mut index = index;
let mut depth = 0;
while index <= origin {
if program[index] as char == '[' {
depth += 1;
} else if program[index] as char == ']' {
depth -= 1;
}
if depth == 0 {
break;
}
index -= 1;
}
if depth != 0 {
return (None, lma, lmv);
}
(Some(index), lma, index)
}
fn parse_byte(s: &str) -> Result<u8, String> {
let mut cs = s.chars();
match cs.next() {
None => Err("Expected input got got none".to_owned()),
Some('\\') => match cs.collect::<String>().parse::<u8>() {
Ok(val) => Ok(val),
Err(e) => Err(e.to_string()),
},
Some(c) => Ok(c as u8),
}
}
pub fn interpret(mem: &mut Vec<u8>, program: &[u8]) -> i32 {
let mut mem_ptr: usize = 0;
let mut ins_ptr: usize = 0;
let mut last_match_left_arg = 0;
let mut last_match_left_val = 0;
let mut last_match_right_arg = usize::MAX;
let mut last_match_right_val = 0;
let mut input = io::stdin().lock().lines();
if mem.is_empty() {
mem.push(0);
}
while ins_ptr < program.len() {
match program[ins_ptr] as char {
'>' => {
mem_ptr += 1;
let mem_len = mem.len();
if mem_ptr == mem_len {
mem.push(0);
continue;
}
assert!(mem_ptr < mem.len()); }
'<' => {
let new_mem_ptr = mem_ptr - 1;
if new_mem_ptr > mem_ptr {
return 4;
}
mem_ptr = new_mem_ptr;
}
'+' => mem[mem_ptr] += 1,
'-' => mem[mem_ptr] -= 1,
'.' => {
print!("{}", mem[mem_ptr] as char);
}
',' => {
println!();
io::stdout().flush().expect("Failed to flush stdout (???)");
mem[mem_ptr] = parse_byte(
&mut input
.next()
.expect("Failed to read stdin (???)")
.unwrap_or_else(|e| {
eprintln!("{e}");
exit(1)
}),
)
.unwrap_or_else(|e| {
eprintln!("{e}");
exit(1);
});
}
'[' => {
if mem[mem_ptr] == 0 {
match match_right(ins_ptr, program, last_match_right_arg, last_match_right_val)
{
(0, _, _) => return 4,
(n, lma, lmv) => {
ins_ptr = n;
last_match_right_arg = lma;
last_match_right_val = lmv;
}
}
}
}
']' => {
if mem[mem_ptr] != 0 {
match match_left(ins_ptr, program, last_match_left_arg, last_match_left_val) {
(None, _, _) => return 4,
(Some(n), lma, lmv) => {
ins_ptr = n;
last_match_left_arg = lma;
last_match_left_val = lmv;
}
}
}
}
_ => {}
}
ins_ptr += 1;
}
io::stdout().flush().expect("Failed to flush stdout (???)");
0
}