Answer

Rust

I think this one works right...

const PROGRAM: &str = r#"
    ++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.
"#;
const INCREMENT_DATAPOINTER: char = '>';
const DECREMENT_DATAPOINTER: char = '<';
const INCREMENT_BYTE: char = '+';
const DECREMENT_BYTE: char = '-';
const OUTPUT_BYTE: char = '.';
const INPUT_BYTE: char = ',';
const JUMP_FORWARD: char = '[';
const JUMP_BACKWARD: char = ']';

enum Instruction {
    IncrementDataPointer,
    DecrementDataPointer,
    IncrementByte,
    DecrementByte,
    OutputByte,
    InputByte,
    JumpBlock(Vec<Instruction>),
}

fn parse<T: AsRef<str>>(input: T) -> Result<Vec<Instruction>, &'static str> {
    let mut instructions = Vec::new();
    let mut chars = input.as_ref().chars().peekable();
    while let Some(&c) = chars.peek() {
        match c {
            INCREMENT_DATAPOINTER => instructions.push(Instruction::IncrementDataPointer),
            DECREMENT_DATAPOINTER => instructions.push(Instruction::DecrementDataPointer),
            INCREMENT_BYTE => instructions.push(Instruction::IncrementByte),
            DECREMENT_BYTE => instructions.push(Instruction::DecrementByte),
            OUTPUT_BYTE => instructions.push(Instruction::OutputByte),
            INPUT_BYTE => instructions.push(Instruction::InputByte),
            JUMP_FORWARD => {
                chars.next();
                let mut block = Vec::new();
                while let Some(&c) = chars.peek() {
                    block.push(c);

                    if c == JUMP_BACKWARD {
                        break;
                    }
                    chars.next();
                }
    
                if block.last() != Some(&JUMP_BACKWARD) {
                    return Err("Expected ']' to close block");
                }

                let parsed_block = parse(block.iter().collect::<String>().as_str())?;
                instructions.push(Instruction::JumpBlock(parsed_block));
            }
            _ => (),
        }
        chars.next();
    }
    Ok(instructions)
}

fn process_instruction(instruction: &Instruction, data: &mut Vec<u8>, data_pointer: &mut usize) {
    match instruction {
        Instruction::IncrementDataPointer => increment_data_pointer(data_pointer),
        Instruction::DecrementDataPointer => decrement_data_pointer(data_pointer),
        Instruction::IncrementByte => increment_byte(data, *data_pointer),
        Instruction::DecrementByte => decrement_byte(data, *data_pointer),
        Instruction::OutputByte => output_byte(data, *data_pointer),
        Instruction::InputByte => input_byte(data, *data_pointer),
        Instruction::JumpBlock(ref block) => process_jump_block(block, data, data_pointer),
    }
}

fn increment_data_pointer(data_pointer: &mut usize) {
    *data_pointer += 1;
}

fn decrement_data_pointer(data_pointer: &mut usize) {
    if *data_pointer > 0 {
        *data_pointer -= 1;
    }
}

fn increment_byte(data: &mut Vec<u8>, data_pointer: usize) {
    data[data_pointer] += 1;
}

fn decrement_byte(data: &mut Vec<u8>, data_pointer: usize) {
    data[data_pointer] = data[data_pointer].saturating_sub(1);
}

fn output_byte(data: &mut Vec<u8>, data_pointer: usize) {
    print!("{}", data[data_pointer] as char);
}

fn input_byte(data: &mut Vec<u8>, data_pointer: usize) {
    let mut input = String::new();
    std::io::stdin().read_line(&mut input).unwrap();
    data[data_pointer] = input.chars().next().unwrap() as u8;
}

fn process_jump_block(block: &[Instruction], data: &mut Vec<u8>, data_pointer: &mut usize) {
    while data[*data_pointer] != 0 {
        for instruction in block {
            process_instruction(instruction, data, data_pointer);
        }
    }
}

fn evaluate(instructions: &[Instruction]) {
    let mut data: Vec<u8> = vec![0; 30000];
    let mut data_pointer = 0;
    let mut instruction_pointer = 0;

    while instruction_pointer < instructions.len() {
        process_instruction(&instructions[instruction_pointer], &mut data, &mut data_pointer);
        instruction_pointer += 1;
    }
}
fn main() {
    let instructions = parse(PROGRAM).unwrap();
    evaluate(&instructions);
}