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
use crate::machine::hook::{HookResult, PreExecuteHook};
use crate::machine::instruction::MachineInstruction;
use crate::machine::output_receiver::{NoopOutputReceiver, OutputReceiver};
use crate::machine::register::{HashMapRegister, MachineRegister};
use std::convert::TryFrom;
pub mod hook;
pub mod instruction;
pub mod output_receiver;
pub mod register;
pub struct Machine<I: MachineInstruction, R: MachineRegister, O: OutputReceiver> {
instructions: Vec<I>,
pub register: R,
pub output_receiver: O,
counter: i32,
}
impl<I: MachineInstruction> Machine<I, HashMapRegister, NoopOutputReceiver> {
pub fn new_simple_machine(
instructions: &[I],
) -> Machine<I, HashMapRegister, NoopOutputReceiver> {
Machine {
instructions: instructions.to_vec(),
register: HashMapRegister::default(),
output_receiver: NoopOutputReceiver,
counter: 0,
}
}
}
impl<I, R, O> Machine<I, R, O>
where
I: MachineInstruction,
R: MachineRegister,
O: OutputReceiver,
{
pub fn new_machine(instructions: &[I], register: R, output_receiver: O) -> Machine<I, R, O> {
Machine {
instructions: instructions.to_vec(),
register,
output_receiver,
counter: 0,
}
}
pub fn run<H: PreExecuteHook>(&mut self, pre_execute_hook: &mut H) {
while let Some((idx, instruction)) = self.get_next_instruction() {
match pre_execute_hook.run(self, &instruction, idx) {
HookResult::Proceed => {
self.counter +=
instruction.execute(&mut self.register, &mut self.output_receiver);
}
HookResult::Skip => {}
HookResult::Abort => {
return;
}
}
}
}
fn get_next_instruction(&self) -> Option<(usize, I)> {
usize::try_from(self.counter).ok().and_then(|idx| {
self.instructions
.get(idx)
.map(|instruction| (idx, instruction.clone()))
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::ParseError;
use crate::machine::hook::NoopHook;
use crate::machine::instruction::ParsedMachineInstruction;
#[test]
fn test_machine() {
let instructions = vec![MockInstruction; 3];
let mut machine = Machine::new_simple_machine(&instructions);
machine.run(&mut NoopHook);
assert_eq!(machine.register.read('a'), 30);
}
#[derive(Clone)]
struct MockInstruction;
impl MachineInstruction for MockInstruction {
fn execute<R: MachineRegister, O: OutputReceiver>(
&self,
register: &mut R,
_output_receiver: &mut O,
) -> i32 {
register.increment('a', 10);
1
}
fn from_parsed_machine_instruction(
_parsed: &ParsedMachineInstruction,
) -> Result<Self, ParseError> {
unimplemented!()
}
}
}