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
use instruction::Instruction::*;
use instructions::Instructions;

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum OptimizationLevel {
    // May be room for more optimizations later
    Off,
    On,
}

pub fn apply_optimizations(instructions: &mut Instructions, level: OptimizationLevel) {
    // Optimizers should be grouped by the number of assumptions
    // the optimizer makes about the code
    // The fewer assumptions, the lower the applicable optimization level
    // Optimizers should be ordered appropriately so that they
    // do not conflict or contradict each other
    let optimizers = match level {
        OptimizationLevel::Off => vec![],
        OptimizationLevel::On => vec![
            remove_opposites,
        ],
    };

    for optimize in optimizers {
        optimize(instructions);
    }
}

fn remove_opposites(instructions: &mut Instructions) {
    let mut i = 1;
    while i < instructions.len() {
        let prev = instructions[i - 1];
        let current = instructions[i];

        // Cancel out opposites
        match (prev, current) {
            (Left, Right) | (Right, Left) |
            (Increment, Decrement) | (Decrement, Increment) => {
                instructions.remove(i);
                instructions.remove(i - 1);
                i -= 1;
            },

            // Otherwise just move on
            _ => i += 1,
        }
    }
}