brain-rs 0.1.0

Embeddable brainfuck interpreter
Documentation
use instruction::{Instruction, InstructionType};

#[derive(Debug)]
pub struct Compiler {
    code: String,
    code_length: usize,
    position: usize,
    instructions: Vec<Instruction>
}

impl Compiler {
    pub fn new(code: &str) -> Self {
        Compiler {
            code: code.to_owned(),
            code_length: code.len(),
            position: 0,
            instructions: Vec::new(),
        }
    }

    pub fn compile(&mut self) -> &[Instruction] {
        let mut loop_stack: Vec<usize> = Vec::new();

        while self.position < self.code_length {
            let current = self.code.chars().nth(self.position).unwrap();
            match current {
                '[' => loop_stack.push(self.emit_with_arg(InstructionType::JMP_IF_ZERO, 0)),
                ']' => {
                    let op_ins = loop_stack[loop_stack.len() - 1];
                    loop_stack = loop_stack[..loop_stack.len() - 1].to_vec();
                    let close_ins_pos = self.emit_with_arg(InstructionType::JMP_IF_NOT_ZERO, op_ins);
                    self.instructions[op_ins].argument = close_ins_pos;
                },
                _ => self.compile_foldable_instruction(current, InstructionType::from(current)),
            }
            self.position += 1;
        }
        &self.instructions
    }

    fn compile_foldable_instruction(&mut self, c: char, ins_type: InstructionType) {
        let mut count = 1;
        while self.position < self.code_length - 1 && self.code.chars().nth(self.position + 1).unwrap() == c {
            count += 1;
            self.position += 1;
        }
        self.emit_with_arg(ins_type, count);
    }

    fn emit_with_arg(&mut self, ins_type: InstructionType, arg: usize) -> usize {
        self.instructions.push(Instruction::new(ins_type, self.position, arg));
        self.instructions.len() - 1
    }
}