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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
mod loop_balance;
mod analysis;
mod compiler;
pub use self::compiler::{compile, JitCompilable};
use std::io::{Read, Write};
use std::mem;
use dynasmrt;
use common::{BfResult, Error};
use rts::{self, RtsState};
use state::State;
use traits::Interpretable;
pub struct Program {
code: dynasmrt::ExecutableBuffer,
start: dynasmrt::AssemblyOffset,
}
type EntryFunction<'a> = extern "win64" fn(memory: *mut u8,
memory_size: u64,
rts_state: *mut RtsState<'a>) -> u64;
impl Interpretable for Program {
fn interpret_state<R: Read, W: Write>(&self, mut state: State,
mut input: R, mut output: W)
-> BfResult<()>
{
let mut rts = RtsState::new(&mut input, &mut output);
let f: EntryFunction = unsafe { mem::transmute(self.code.ptr(self.start)) };
let result = f(state.as_mut_ptr(), state.capacity() as u64, &mut rts);;
match result {
rts::OKAY => Ok(()),
rts::UNDERFLOW => Err(Error::PointerUnderflow),
rts::OVERFLOW => Err(Error::PointerOverflow),
_ => panic!(format!("Unknown result code: {}", result)),
}
}
}
#[cfg(test)]
mod tests {
use test_helpers::*;
use common::{BfResult, Error};
#[test]
fn move_right_once() {
assert_parse_interpret(b">", "", Ok(""));
}
#[test]
fn move_left_once() {
assert_parse_interpret(b"<", "", Err(Error::PointerUnderflow));
}
#[test]
fn move_right_forever() {
assert_parse_interpret(b"+[>+]", "", Err(Error::PointerOverflow));
}
#[test]
fn echo_one_byte() {
assert_parse_interpret(b",.", "A", Ok("A"));
}
#[test]
fn inc_echo_one_byte() {
assert_parse_interpret(b",+.", "A", Ok("B"));
}
#[test]
fn hello_world() {
assert_parse_interpret(HELLO_WORLD_SRC, "", Ok("Hello, World!"));
}
#[test]
fn factoring() {
assert_parse_interpret(FACTOR_SRC, "2\n", Ok("2: 2\n"));
assert_parse_interpret(FACTOR_SRC, "3\n", Ok("3: 3\n"));
assert_parse_interpret(FACTOR_SRC, "6\n", Ok("6: 2 3\n"));
assert_parse_interpret(FACTOR_SRC, "100\n", Ok("100: 2 2 5 5\n"));
}
fn assert_parse_interpret(program: &[u8], input: &str, output: BfResult<&str>) {
let program = ::ast::parse_program(program).unwrap();
let program = ::rle::compile(&program);
let program = ::peephole::compile(&program);
let program = ::jit::compile(&program, true);
assert_interpret_result(&program, input.as_bytes(), output.map(|s| s.as_bytes()));
}
}