1use log::{debug, info, warn};
2use std::io::Read;
3
4pub struct Intepreter {
5 code: Vec<u8>,
6 data: Vec<u8>,
7 match_stack: Vec<usize>,
8 code_ptr: usize,
9 data_ptr: usize,
10 max_output_size: usize,
11}
12
13impl Intepreter {
14 pub fn new(code: Vec<u8>, max_data_size: usize, max_output_size: usize) -> Self {
15 debug!("Creating new interpreter with code length: {}", code.len());
16 let mut match_stack = vec![0; code.len()];
17 let mut stack = Vec::new();
18 for (i, &c) in code.iter().enumerate() {
19 if c == 7 {
20 debug!("Found loop start at position {}", i);
21 stack.push(i);
22 } else if c == 8 {
23 if let Some(open) = stack.pop() {
24 debug!("Matching loop end at {} with start at {}", i, open);
25 match_stack[open] = i;
26 match_stack[i] = open;
27 } else {
28 warn!("Unmatched closing bracket at position {}", i);
29 }
30 }
31 }
32
33 if !stack.is_empty() {
34 warn!("Unmatched opening brackets at positions: {:?}", stack);
35 }
36
37 Intepreter {
38 code,
39 data: vec![0; max_data_size],
40 code_ptr: 0,
41 data_ptr: max_data_size / 2,
42 match_stack,
43 max_output_size,
44 }
45 }
46
47 pub fn run(&mut self) -> String {
48 info!("Starting interpreter execution");
49 let mut output = Vec::with_capacity(self.max_output_size);
50
51 while self.code_ptr < self.code.len() {
52 debug!(
53 "State: ptr={}, data_ptr={}, current_op={}, current_value={}",
54 self.code_ptr, self.data_ptr, self.code[self.code_ptr], self.data[self.data_ptr]
55 );
56
57 let mut normal = true;
58 match self.code[self.code_ptr] {
59 1 => self.data_ptr += 1, 2 => self.data_ptr -= 1, 3 => self.data[self.data_ptr] += 1, 4 => self.data[self.data_ptr] -= 1, 5 => output.push(self.data[self.data_ptr] as char), 6 => {
65 warn!("There Shouldn't be any input in this mode");
66 let mut input = [0; 1];
67 std::io::stdin().read_exact(&mut input).unwrap();
68 self.data[self.data_ptr] = input[0]
69 } 7 => {
71 if self.data[self.data_ptr] == 0 {
72 self.code_ptr = self.match_stack[self.code_ptr];
73 normal = false;
74 }
75 } 8 => {
77 if self.data[self.data_ptr] != 0 {
78 self.code_ptr = self.match_stack[self.code_ptr];
79 normal = false;
80 }
81 } _ => {}
83 }
84 if normal {
85 self.code_ptr += 1;
86 }
87 }
88 info!("Execution completed");
89 output.into_iter().collect()
91 }
92}
93
94pub fn brainfuck_to_bytecode(code: &str) -> Vec<u8> {
95 debug!(
96 "Converting brainfuck code to bytecode, length: {}",
97 code.len()
98 );
99 let code = code.chars().filter_map(|c| match c {
100 '>' => Some(1),
101 '<' => Some(2),
102 '+' => Some(3),
103 '-' => Some(4),
104 '.' => Some(5),
105 ',' => Some(6),
106 '[' => Some(7),
107 ']' => Some(8),
108 _ => None,
109 });
110 code.collect()
111}
112
113pub fn ook_to_bytecode(code: &str) -> Vec<u8> {
114 debug!("Converting Ook code to bytecode, length: {}", code.len());
115 let words: Vec<&str> = code.split_whitespace().collect();
116
117 let mut commands = Vec::new();
118 for chunk in words.chunks(2) {
119 if chunk.len() == 2 {
120 commands.push((chunk[0].to_string(), chunk[1].to_string()));
121 }
122 }
123 commands
124 .iter()
125 .filter_map(|(first, second)| {
126 match (first.as_str(), second.as_str()) {
127 ("Ook.", "Ook?") => Some(1), ("Ook?", "Ook.") => Some(2), ("Ook.", "Ook.") => Some(3), ("Ook!", "Ook!") => Some(4), ("Ook!", "Ook.") => Some(5), ("Ook.", "Ook!") => Some(6), ("Ook!", "Ook?") => Some(7), ("Ook?", "Ook!") => Some(8), _ => None,
136 }
137 })
138 .collect()
139}
140
141pub fn parse_short_ook_commands(code: &str) -> Vec<u8> {
142 let iter: Vec<char> = code
143 .chars()
144 .filter(|c| matches!(c, '.' | '?' | '!'))
145 .collect();
146 let mut commands = vec![];
147 for chunk in iter.chunks(2) {
148 if chunk.len() == 2 {
149 commands.push((chunk[0], chunk[1]));
150 }
151 }
152 commands
153 .iter()
154 .filter_map(|(first, second)| match (*first, *second) {
155 ('.', '?') => Some(1),
156 ('?', '.') => Some(2),
157 ('.', '.') => Some(3),
158 ('!', '!') => Some(4),
159 ('!', '.') => Some(5),
160 ('.', '!') => Some(6),
161 ('!', '?') => Some(7),
162 ('?', '!') => Some(8),
163 _ => None,
164 })
165 .collect()
166}