1use instruction::{Instruction, InstructionType};
2
3#[derive(Debug)]
4pub struct Compiler {
5 code: String,
6 code_length: usize,
7 position: usize,
8 instructions: Vec<Instruction>
9}
10
11impl Compiler {
12 pub fn new(code: &str) -> Self {
13 Compiler {
14 code: code.to_owned(),
15 code_length: code.len(),
16 position: 0,
17 instructions: Vec::new(),
18 }
19 }
20
21 pub fn compile(&mut self) -> &[Instruction] {
22 let mut loop_stack: Vec<usize> = Vec::new();
23
24 while self.position < self.code_length {
25 let current = self.code.chars().nth(self.position).unwrap();
26 match current {
27 '[' => loop_stack.push(self.emit_with_arg(InstructionType::JMP_IF_ZERO, 0)),
28 ']' => {
29 let op_ins = loop_stack[loop_stack.len() - 1];
30 loop_stack = loop_stack[..loop_stack.len() - 1].to_vec();
31 let close_ins_pos = self.emit_with_arg(InstructionType::JMP_IF_NOT_ZERO, op_ins);
32 self.instructions[op_ins].argument = close_ins_pos;
33 },
34 _ => self.compile_foldable_instruction(current, InstructionType::from(current)),
35 }
36 self.position += 1;
37 }
38 &self.instructions
39 }
40
41 fn compile_foldable_instruction(&mut self, c: char, ins_type: InstructionType) {
42 let mut count = 1;
43 while self.position < self.code_length - 1 && self.code.chars().nth(self.position + 1).unwrap() == c {
44 count += 1;
45 self.position += 1;
46 }
47 self.emit_with_arg(ins_type, count);
48 }
49
50 fn emit_with_arg(&mut self, ins_type: InstructionType, arg: usize) -> usize {
51 self.instructions.push(Instruction::new(ins_type, self.position, arg));
52 self.instructions.len() - 1
53 }
54}