crypto_brainfuck/utils/
brainfuck.rs1pub const MAX_MEMORY: usize = 30000;
3
4#[derive(Debug, Copy, Clone, Eq, PartialEq)]
5pub enum Op {
6 IncrementPtr,
7 DecrementPtr,
8 IncrementMemory,
9 DecrementMemory,
10 ReadByte,
11 WriteByte,
12 JumpForward,
13 JumpBackward,
14}
15
16impl Op {
17 fn from_char(character: char) -> Option<Self> {
18 match character {
19 '>' => Some(Op::IncrementPtr),
20 '<' => Some(Op::DecrementPtr),
21 '+' => Some(Op::IncrementMemory),
22 '-' => Some(Op::DecrementMemory),
23 '.' => Some(Op::WriteByte),
24 ',' => Some(Op::ReadByte),
25 '[' => Some(Op::JumpForward),
26 ']' => Some(Op::JumpBackward),
27 _ => None,
28 }
29 }
30}
31
32pub struct Program {
33 pub instructions: Vec<Op>,
34}
35
36impl Program {
37 pub fn from_string(string: &str) -> Self {
38 let ops: Vec<Op> = string.chars().map(|c| -> Option<Op> { Op::from_char(c) }).filter_map(|x| x).collect();
39
40 Program { instructions: ops }
41 }
42
43 pub fn find_matching_jump_end(&self, jump_start_pos: usize) -> usize {
44 let mut pos = jump_start_pos;
45 let mut level = 0;
46
47 loop {
48 match self.instructions[pos] {
49 Op::JumpForward => level += 1,
50 Op::JumpBackward => level -= 1,
51 _ => (),
52 }
53
54 if level == 0 {
55 return pos;
56 }
57 if pos >= self.instructions.len() {
58 panic!("unbalanced parentheses")
59 }
60 pos += 1
61 }
62 }
63
64 pub fn find_matching_jump_start(&self, jump_end_pos: usize) -> usize {
65 let mut pos = jump_end_pos;
66 let mut level = 0;
67
68 loop {
69 match self.instructions[pos] {
70 Op::JumpForward => level -= 1,
71 Op::JumpBackward => level += 1,
72 _ => (),
73 }
74
75 if level == 0 {
76 return pos;
77 }
78 if pos == 0 {
79 panic!("unbalanced parentheses")
80 }
81 pos -= 1
82 }
83 }
84}
85
86#[cfg(test)]
87mod test {
88 use super::*;
89
90 #[test]
91 fn check_supported_ops() {
92 let program = Program::from_string("><+-.,[]");
93
94 assert_eq!(program.instructions[0], Op::IncrementPtr);
95 assert_eq!(program.instructions[1], Op::DecrementPtr);
96 assert_eq!(program.instructions[2], Op::IncrementMemory);
97 assert_eq!(program.instructions[3], Op::DecrementMemory);
98 assert_eq!(program.instructions[4], Op::WriteByte);
99 assert_eq!(program.instructions[5], Op::ReadByte);
100 assert_eq!(program.instructions[6], Op::JumpForward);
101 assert_eq!(program.instructions[7], Op::JumpBackward);
102 }
103
104 #[test]
105 fn ignores_comments() {
106 let program = Program::from_string(">loop[-]");
107
108 assert_eq!(program.instructions.len(), 4);
109 assert_eq!(program.instructions[0], Op::IncrementPtr);
110 assert_eq!(program.instructions[1], Op::JumpForward);
111 assert_eq!(program.instructions[2], Op::DecrementMemory);
112 assert_eq!(program.instructions[3], Op::JumpBackward);
113 }
114
115 #[test]
116 fn find_matching_parentheses() {
117 let program = Program::from_string("[[][]]");
118
119 assert_eq!(program.find_matching_jump_end(0), 5);
120 assert_eq!(program.find_matching_jump_start(5), 0);
121
122 assert_eq!(program.find_matching_jump_end(3), 4);
123 assert_eq!(program.find_matching_jump_start(4), 3);
124 }
125}