1 module optimize;
2 
3 import brainfuck;
4 
5 import std.algorithm.iteration;
6 import std.algorithm.searching;
7 import std.array;
8 import std.range;
9 import std.conv;
10 
11 BrainfuckInstruction[] clear_opt(BrainfuckInstruction[] insts) {
12     return insts.map!(inst => delegate BrainfuckInstruction() {
13         if(auto loop = cast(Loop) inst) {
14             auto loop_insts = loop.insts;
15             if(loop_insts.length == 1) {
16                 if(auto modify = cast(Modify) loop_insts[0]) {
17                     if(modify.amt == -1) return new Clear();
18                 }
19             }
20 
21             return new Loop(clear_opt(loop.insts));
22         }
23 
24         return inst;
25     }()).array;
26 }
27 
28 BrainfuckInstruction[] balanced_opt(BrainfuckInstruction[] insts) {
29     return insts.map!(inst => delegate BrainfuckInstruction() {
30         if(auto loop = cast(Loop) inst) {
31             auto loop_insts = loop.insts;
32             if(loop_insts.all!(loop_inst => (cast(Modify) loop_inst) || (cast(Select) loop_inst))) {
33                 if(loop_insts
34                     .filter!(loop_inst => cast(Select) loop_inst)
35                     .map!(loop_inst => (cast(Select) loop_inst).amt)
36                     .sum() == 0) {
37                     int[int] ms;
38                     int pointer = 0;
39                     
40                     foreach(loop_inst; loop_insts) {
41                         if(auto modify = cast(Modify) loop_inst) {
42                             ms[pointer] += modify.amt;
43                         } else if(auto select = cast(Select) loop_inst) {
44                             pointer += select.amt;
45                         }
46                     }
47 
48                     if(ms[0] == -1) {
49                         ms.remove(0);
50                         return new MoveLoop(ms);
51                     }
52                 }
53             }
54 
55             return new Loop(balanced_opt(loop.insts));
56         }
57 
58         return inst;
59     }()).array;
60 }