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
use super::*;
use peephole;
use common::{Count, Instruction};
pub trait BytecodeCompilable {
fn with_peephole<F, R>(&self, k: F) -> R
where F: FnOnce(&peephole::Program) -> R;
fn bytecode_compile(&self) -> Box<Program> {
self.with_peephole(compile)
}
}
pub fn compile(src: &[peephole::Statement]) -> Box<Program> {
let mut compiler = Compiler::new();
compiler.compile(src);
compiler.into_program()
}
pub struct Compiler {
instructions: Vec<Instruction>,
}
impl Compiler {
pub fn new() -> Self {
Compiler {
instructions: Vec::new(),
}
}
pub fn compile(&mut self, src: &[peephole::Statement]) {
use peephole::Statement as Src;
use common::Instruction as Obj;
for instruction in src {
match *instruction {
Src::Instr(instruction) => self.issue(instruction),
Src::Loop(ref body) => {
let begin_pc = self.instructions.len();
self.issue(Obj::JumpZero(0));
self.compile(body);
let end_pc = self.instructions.len();
self.issue(Obj::JumpNotZero(usize_to_count(begin_pc)));
self.instructions[begin_pc] = Obj::JumpZero(usize_to_count(end_pc));
}
}
}
}
pub fn into_program(self) -> Box<Program> {
self.instructions.into_boxed_slice()
}
fn issue(&mut self, instruction: Instruction) {
self.instructions.push(instruction);
}
}
pub fn usize_to_count(count: usize) -> Count {
let result: Count = count as Count;
assert_eq!(result as usize, count);
result
}
impl BytecodeCompilable for peephole::Program {
fn with_peephole<F, R>(&self, k: F) -> R
where F: FnOnce(&peephole::Program) -> R
{
k(self)
}
}
impl<T: peephole::PeepholeCompilable + ?Sized> BytecodeCompilable for T {
fn with_peephole<F, R>(&self, k: F) -> R
where F: FnOnce(&peephole::Program) -> R
{
k(&self.peephole_compile())
}
}