brainfuck/
instruction.rs

1use std::fmt;
2
3#[derive(Debug, PartialEq, Eq, Clone, Copy)]
4pub enum Instruction {
5    // ">" - increment the pointer (move it to the "right")
6    Right(usize),
7    // "<" - decrement the pointer (move it to the "left")
8    Left(usize),
9    // "+" - increment the byte at the pointer
10    Increment(usize),
11    // "-" - decrement the byte at the pointer
12    Decrement(usize),
13    // "." - output the byte at the pointer
14    Write,
15    // "," - input a byte and store it in the byte at the pointer
16    Read,
17    // "[" - jump forward past the matching ] if the byte at the pointer is zero
18    JumpForwardIfZero {
19        // Store the instruction index of the matching parenthesis
20        // Lazily initialized as needed
21        matching: Option<usize>,
22    },
23    // "]" - jump backward to the matching [ unless the byte at the pointer is zero
24    JumpBackwardUnlessZero {
25        // Store the instruction index of the matching parenthesis
26        // Strictly initialized when the program is loaded into memory
27        matching: usize,
28    },
29}
30
31impl fmt::Display for Instruction {
32    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
33        f.write_str(match *self {
34            Instruction::Right(n) => format_instruction(">", n),
35            Instruction::Left(n) => format_instruction("<", n),
36            Instruction::Increment(n) => format_instruction("+", n),
37            Instruction::Decrement(n) => format_instruction("-", n),
38            Instruction::Write => ".".to_owned(),
39            Instruction::Read => ",".to_owned(),
40            Instruction::JumpForwardIfZero { .. } => "[".to_owned(),
41            Instruction::JumpBackwardUnlessZero { .. } => "]".to_owned(),
42        }.as_ref())
43    }
44}
45
46#[inline]
47fn format_instruction(instr: &str, n: usize) -> String {
48    format!("{}{}", instr, if n > 1 {format!("{}", n)} else {"".to_owned()})
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54
55    #[test]
56    fn display() {
57        assert_eq!(Instruction::Right(1).to_string(), ">");
58        assert_eq!(Instruction::Right(2).to_string(), ">2");
59        assert_eq!(Instruction::Right(5).to_string(), ">5");
60
61        assert_eq!(Instruction::Left(1).to_string(), "<");
62        assert_eq!(Instruction::Left(2).to_string(), "<2");
63        assert_eq!(Instruction::Left(5).to_string(), "<5");
64
65        assert_eq!(Instruction::Increment(1).to_string(), "+");
66        assert_eq!(Instruction::Increment(2).to_string(), "+2");
67        assert_eq!(Instruction::Increment(5).to_string(), "+5");
68
69        assert_eq!(Instruction::Decrement(1).to_string(), "-");
70        assert_eq!(Instruction::Decrement(2).to_string(), "-2");
71        assert_eq!(Instruction::Decrement(5).to_string(), "-5");
72
73        assert_eq!(Instruction::Write.to_string(), ".");
74        assert_eq!(Instruction::Read.to_string(), ",");
75
76        assert_eq!(Instruction::JumpForwardIfZero {matching: None}.to_string(), "[");
77        assert_eq!(Instruction::JumpBackwardUnlessZero {matching: 0}.to_string(), "]");
78    }
79}