1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
use std::io::{Read, Write}; use state::State; use common::BfResult; use traits::Interpretable; use super::*; impl Interpretable for Program { fn interpret_state<R: Read, W: Write>( &self, mut state: State, mut input: R, mut output: W) -> BfResult<()> { interpret(self, &mut state, &mut input, &mut output) } } fn interpret<R, W>(instructions: &[Statement], state: &mut State, input: &mut R, output: &mut W) -> BfResult<()> where R: Read, W: Write { for instruction in instructions { interpret_instruction(instruction, state, input, output)?; } Ok(()) } fn interpret_instruction<R, W>(instructions: &Statement, state: &mut State, input: &mut R, output: &mut W) -> BfResult<()> where R: Read, W: Write { use super::Statement::*; use common::Instruction::*; match *instructions { Instr(Left(count)) => state.left(count as usize)?, Instr(Right(count)) => state.right(count as usize)?, Instr(Add(amount)) => state.up(amount), Instr(In) => state.read(input), Instr(Out) => state.write(output), Instr(SetZero) => state.store(0), Instr(OffsetAddRight(offset)) => { let value = state.load(); if value != 0 { state.store(0); state.up_pos_offset(offset as usize, value)?; } } Instr(OffsetAddLeft(offset)) => { let value = state.load(); if value != 0 { state.store(0); state.up_neg_offset(offset as usize, value)?; } } Instr(FindZeroRight(skip)) => { while state.load() != 0 { state.right(skip as usize)?; } } Instr(FindZeroLeft(skip)) => { while state.load() != 0 { state.left(skip as usize)?; } } Instr(JumpZero(_)) | Instr(JumpNotZero(_)) => panic!("unexpected jump instruction"), Loop(ref body) => { while state.load() != 0 { interpret(body, state, input, output)?; } } } Ok(()) } #[cfg(test)] mod tests { use test_helpers::*; #[test] fn hello_world() { assert_parse_interpret(HELLO_WORLD_SRC, "", "Hello, World!"); } #[test] fn factoring() { assert_parse_interpret(FACTOR_SRC, "2\n", "2: 2\n"); assert_parse_interpret(FACTOR_SRC, "3\n", "3: 3\n"); assert_parse_interpret(FACTOR_SRC, "6\n", "6: 2 3\n"); assert_parse_interpret(FACTOR_SRC, "100\n", "100: 2 2 5 5\n"); } fn assert_parse_interpret(program: &[u8], input: &str, output: &str) { let program = ::ast::parse_program(program).unwrap(); let program = ::rle::compile(&program); let program = ::peephole::compile(&program); assert_interpret(&*program, input.as_bytes(), output.as_bytes()); } }