brain/
machine.rs

1use std::io::{self, Read, Write};
2use std::fmt::{self, Display};
3use instruction::{Instruction, InstructionType};
4
5pub struct Machine<'a, R: Read, W: Write> {
6    code: &'a [Instruction],
7    ip: usize,
8    memory: [usize; 30000],
9    dp: usize,
10    input: R,
11    output: W,
12    read_buf: Vec<u8>,
13}
14
15impl<'a, R: Read, W: Write> Display for Machine<'a, R, W> {
16    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
17        write!(f,
18            "Machine ( code: {:?}, dp: {:?}, buf: {:?} )",
19            self.code, self.dp, self.read_buf
20        )
21    }
22}
23
24impl<'a, R: Read, W: Write> Machine<'a, R, W> {
25    pub fn new(ins: &'a [Instruction], inp: R, out: W) -> Self {
26        Machine {
27            code: ins,
28            ip: 0,
29            memory: [0; 30000],
30            dp: 0,
31            input: inp,
32            output: out,
33            read_buf: Vec::new(),
34        }
35    }
36
37    pub fn execute(&mut self) -> Result<(), String> {
38        let mut line_count = (1, 1);
39        while self.ip < self.code.len() {
40            let ins = &self.code[self.ip];
41
42            match ins.ins_type {
43                InstructionType::PLUS => self.memory[self.dp] += ins.argument,
44                InstructionType::MINUS => self.memory[self.dp] -= ins.argument,
45                InstructionType::RIGHT => self.dp += ins.argument,
46                InstructionType::LEFT => self.dp -= ins.argument,
47                InstructionType::PUT_CHAR => {
48                    for _ in 0..ins.argument {
49                        match self.put_char() {
50                            Ok(_) => continue,
51                            Err(e) => panic!(e),
52                        }
53                    }
54                },
55                InstructionType::READ_CHAR => {
56                   for _ in 0..ins.argument {
57                        self.read_char();
58                    }
59                },
60                InstructionType::JMP_IF_ZERO => {
61                    if self.memory[self.dp] == 0 {
62                        self.ip = ins.argument as usize;
63                        continue
64                    }
65                },
66                InstructionType::JMP_IF_NOT_ZERO => {
67                    if self.memory[self.dp] != 0 {
68                        self.ip = ins.argument as usize;
69                        continue
70                    }
71                },
72                InstructionType::NEW_LINE => {
73                    self.ip += ins.argument;
74                    line_count.0 += ins.argument;
75                    line_count.1 = ins.position;
76                    continue
77                },
78                InstructionType::INVALID => {
79                    return Err(format!("Invalid token at line {}, char {}", line_count.0, ins.position - line_count.1));
80                },
81            }
82            self.ip += 1;
83        }
84        Ok(())
85    }
86
87    fn read_char(&mut self) {
88        let c = self.input.by_ref()
89            .bytes()
90            .next().and_then(|result| result.ok())
91            .map(|c| c as u8).unwrap();
92
93        self.read_buf.push(c);
94        self.memory[self.dp] = *self.read_buf.last().unwrap() as usize;
95    }
96
97    fn put_char(&mut self) -> io::Result<usize> {
98        self.read_buf.push(self.memory[self.dp] as u8);
99
100        match self.read_buf.last() {
101            Some(c) => self.output.write(&[c.clone()]),
102            None => Ok(0),
103        }
104    }
105}