1use std::io::{Read, Write};
2use std::collections::VecDeque;
3
4use super::Instruction;
5
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct InterpreterState<'a> {
8 pub current_instruction: usize,
12 pub instruction: Instruction,
14 pub current_pointer: usize,
16 pub memory: &'a VecDeque<u8>,
18}
19
20pub fn interpret<I, O, F>(mut inp: I, mut out: O, mut program: Vec<Instruction>, mut callback: F)
22 where I: Read, O: Write,
23 F: FnMut(InterpreterState) {
24
25 let mut buffer: VecDeque<u8> = VecDeque::new();
26 buffer.push_back(0u8);
28
29 let mut pointer: usize = 0;
31 let mut next_instruction: usize = 0;
33
34 loop {
35 if next_instruction >= program.len() {
36 break;
37 }
38 let current_instruction = next_instruction;
39 let mut instr = program[current_instruction];
40 next_instruction += 1;
41
42 match instr {
43 Instruction::Right(amount) => {
44 pointer += amount;
45 while pointer >= buffer.len() {
46 buffer.push_back(0u8);
47 }
48 },
49 Instruction::Left(amount) => {
50 if amount > pointer {
51 for _ in 0..(amount - pointer) {
52 buffer.push_front(0u8);
53 }
54 pointer = 0;
55 }
56 else {
57 pointer -= amount;
58 }
59 },
60 Instruction::Increment(amount) => buffer[pointer] = buffer[pointer].wrapping_add(amount as u8),
61 Instruction::Decrement(amount) => buffer[pointer] = buffer[pointer].wrapping_sub(amount as u8),
62 Instruction::Write => out.write_all(&[buffer[pointer]]).expect("Could not output"),
63 Instruction::Read => {
64 let mut inbuffer: [u8; 1] = [0];
65 let res = inp.read_exact(&mut inbuffer[0..1]);
66 if res.is_ok() {
67 buffer[pointer] = inbuffer[0];
68 }
69 else {
70 buffer[pointer] = 0;
71 }
72 },
73 Instruction::JumpForwardIfZero {ref mut matching} => {
74 if buffer[pointer] == 0 {
75 next_instruction = matching.unwrap_or_else(|| fill_matching(&mut program, next_instruction - 1));
76 }
77 },
78 Instruction::JumpBackwardUnlessZero {matching} => {
79 if buffer[pointer] != 0 {
80 next_instruction = matching;
81 }
82 },
83 }
84
85 callback(InterpreterState {
86 current_instruction,
87 instruction: instr,
88 current_pointer: pointer,
89 memory: &buffer,
90 });
91 }
92}
93
94fn fill_matching(mut program: &mut Vec<Instruction>, start: usize) -> usize {
101 use super::MAX_NESTED_JUMPS;
102 let mut jumps = VecDeque::with_capacity(MAX_NESTED_JUMPS);
103
104 let program_size = program.len();
105 let mut current = start;
106 loop {
107 if current >= program_size {
108 panic!("Mismatched `[` instruction");
109 }
110
111 match program[current] {
112 Instruction::JumpForwardIfZero { .. } => jumps.push_back(current),
113 Instruction::JumpBackwardUnlessZero { .. } => {
114 let last_forward = jumps.pop_back().expect("Mismatched `]` instruction");
115 match program[last_forward] {
116 Instruction::JumpForwardIfZero {ref mut matching} => {
117 debug_assert!(matching.is_none(),
118 "matching was already set which means this function ran needlessly");
119 *matching = Some(current + 1);
120 },
121 _ => unreachable!(),
122 }
123 },
124 _ => {},
125 };
126
127 if jumps.is_empty() {
128 break;
129 }
130
131 current += 1;
132 }
133
134 current + 1
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140 use super::super::Instruction::*;
141
142 use std::collections::VecDeque;
143
144 #[test]
145 fn basic_movements() {
146 assert_eq!(test_interpret_output(vec![
148 Increment(1),
149 Right(1),
150 Increment(2),
151 Right(1),
152 Increment(3),
153 Write,
154 Left(1),
155 Write,
156 Left(1),
157 Write,
158 ]), vec![3, 2, 1]);
159 }
160
161 #[test]
162 fn wrapping() {
163 assert_eq!(test_interpret_output(vec![
164 Write,
165 Decrement(1),
166 Write,
167 Increment(2),
168 Write,
169 Increment(256),
170 Write,
171 Decrement(255),
172 Write,
173 Decrement(1),
174 Write,
175 Decrement(1),
176 Write,
177 Decrement(1),
178 Write,
179 Increment(1),
180 Write,
181 Increment(1),
182 Write,
183 Increment(255 * 2),
184 Write,
185 Decrement(255 * 2),
186 Write,
187 ]), vec![0, 255, 1, 1, 2, 1, 0, 255, 0, 1, 255, 1]);
188 }
189
190 #[test]
191 fn move_left_past_zero() {
192 assert_eq!(test_interpret_output(vec![
196 Increment(1),
197 Right(1),
198 Left(4),
199 Right(3),
200 Left(3),
201 Right(3),
202 Increment(1),
203 Write,
204 ]), vec![2]);
205 }
206
207 #[test]
208 fn move_right_past_capacity() {
209 assert_eq!(test_interpret_output(vec![
210 Increment(1),
211 Right(10),
212 Increment(1),
214 Left(20),
215 Right(20),
216 Left(10),
217 Right(15),
218 Left(15),
219 Increment(1),
220 Write,
221 ]), vec![2]);
222 }
223
224 #[test]
225 fn skip_first_loop() {
226 assert_eq!(test_interpret_output(vec![
229 JumpForwardIfZero {matching: None},
230 Right(1),
231 Left(1),
232 Increment(1),
233 Decrement(2),
234 Write,
235 Read,
236 JumpBackwardUnlessZero {matching: 1},
237 ]), vec![]);
238 }
239
240 #[test]
241 fn reading_input() {
242 assert_eq!(test_interpret_with_input(vec![
243 Write,
244 Read,
245 Write,
246 Decrement(1),
247 Write,
248 Read,
249 Write,
250 Increment(1),
251 Write,
252 Right(1),
253 Read, Read,
255 Right(1),
256 Read,
257 Right(1),
258 Read,
259 Left(2),
260 Write,
261 Right(1),
262 Write,
263 Right(1),
264 Write,
265 Left(3), Write,
267 Read, Write,
269 Read,
270 Read,
271 Read,
272 Read,
273 Read,
274 Read,
275 Read,
276 Write,
277 ], &[ 5,
279 0,
280 8,
281 17,
282 32,
283 49,
284 ]), vec![0, 5, 4, 0, 1, 17, 32, 49, 1, 0, 0]);
285 }
286
287 #[test]
288 fn basic_looping() {
289 let x = 13;
292 let y = 15;
293 assert_eq!(test_interpret_output(vec![
294 Increment(x),
295 JumpForwardIfZero {matching: None},
296 Right(1),
297 Increment(y),
298 Left(1),
299 Decrement(1),
300 JumpBackwardUnlessZero {matching: 2},
301 Right(1),
302 Write,
303 ]), vec![(x * y) as u8]);
304 }
305
306 #[test]
307 fn nested_loops() {
308 let x = 13;
311 let y = 15;
312 let z = 2;
313 assert_eq!(test_interpret_output(vec![
314 Increment(x),
315 JumpForwardIfZero {matching: None},
316 Right(1),
317 Increment(y),
318 JumpForwardIfZero {matching: None},
319 Right(1),
320 Increment(z),
321 Left(1),
322 Decrement(1),
323 JumpBackwardUnlessZero {matching: 5},
324 Left(1),
325 Decrement(1),
326 JumpBackwardUnlessZero {matching: 2},
327 Right(2),
328 Write,
329 ]), vec![(x * y * z) as u8]);
330 }
331
332 #[test]
333 fn hello_world() {
334 use super::super::{precompile, OptimizationLevel};
335
336 let source: Vec<u8> = include_bytes!("../examples/hello-world.bf").to_vec();
338 let program = precompile(source.iter(), OptimizationLevel::Off);
339 assert_eq!(test_interpret_output(program),
340 b"Hello World!\n");
341
342 let program = precompile(source.iter(), OptimizationLevel::Speed);
343 assert_eq!(test_interpret_output(program),
344 b"Hello World!\n");
345 }
346
347 #[test]
348 #[should_panic(expected = "Mismatched `[` instruction")]
349 fn mismatched_jumps() {
350 test_interpret_output(vec![
351 JumpForwardIfZero {matching: None},
352 ]);
353 }
354
355 #[test]
356 fn callback_behaviour() {
357 let mut inp: &[u8] = &[];
358 let mut out = Vec::new();
359 let program = vec![
360 Right(4),
361 Left(5),
362 Increment(2),
363 JumpForwardIfZero {matching: None},
364 Decrement(1),
365 JumpBackwardUnlessZero {matching: 4},
366 ];
367 let states = vec![
368 (0, Right(4), 4, vec![0, 0, 0, 0, 0].into()),
369 (1, Left(5), 0, vec![0, 0, 0, 0, 0, 0].into()),
370 (2, Increment(2), 0, vec![2, 0, 0, 0, 0, 0].into()),
371 (3, JumpForwardIfZero {matching: None}, 0, vec![2, 0, 0, 0, 0, 0].into()),
372 (4, Decrement(1), 0, vec![1, 0, 0, 0, 0, 0].into()),
373 (5, JumpBackwardUnlessZero {matching: 4}, 0, vec![1, 0, 0, 0, 0, 0].into()),
374 (4, Decrement(1), 0, vec![0, 0, 0, 0, 0, 0].into()),
375 (5, JumpBackwardUnlessZero {matching: 4}, 0, vec![0, 0, 0, 0, 0, 0].into()),
376 ];
377 let mut states: VecDeque<_> = states.iter().map(|&(current_instruction, instruction, current_pointer, ref memory)| {
378 InterpreterState {current_instruction, instruction, current_pointer, memory}
379 }).collect();
380
381 interpret(&mut inp, &mut out, program, |state| {
382 let expected = states.pop_front().expect("callback was called unexpectedly");
383 assert_eq!(expected, state, "Failed with {} states left", states.len());
384 });
385
386 assert!(states.is_empty());
387 assert_eq!(out, vec![]);
388 }
389
390 fn test_interpret_output(program: Vec<Instruction>) -> Vec<u8> {
391 let inp: &[u8] = &[];
392 test_interpret_with_input(program, inp)
393 }
394
395 fn test_interpret_with_input(program: Vec<Instruction>, mut inp: &[u8]) -> Vec<u8> {
396 let mut out = Vec::new();
397 interpret(&mut inp, &mut out, program, |_| {});
398 out
399 }
400}