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 alias Counts = size_t[string]; 12 13 Counts count_instructions(BrainfuckInstruction[] insts) { 14 Counts counts; 15 16 foreach(inst; insts) { 17 counts[typeid(inst).toString]++; 18 if(auto loop = cast(Loop) inst) { 19 auto inner_counts = count_instructions(loop.insts); 20 add_counts(counts, inner_counts); 21 } else if(auto if_bf = cast(If) inst) { 22 auto inner_counts = count_instructions(if_bf.insts); 23 add_counts(counts, inner_counts); 24 } else if(auto unrolled = cast(UnrolledLoop) inst) { 25 auto inner_counts = count_instructions(unrolled.insts); 26 add_counts(counts, inner_counts); 27 } 28 } 29 30 return counts; 31 } 32 33 void add_counts(Counts dst, Counts src) { 34 foreach(k, v; src) { 35 dst[k] += v; 36 } 37 } 38 39 BrainfuckInstruction[] clear_opt(BrainfuckInstruction[] insts) { 40 return insts.map!(delegate BrainfuckInstruction(inst) { 41 if(auto loop = cast(Loop) inst) { 42 auto loop_insts = loop.insts; 43 if(loop_insts.length == 1) { 44 if(auto modify = cast(Modify) loop_insts[0]) { 45 if(modify.amt == -1) return new Clear; 46 } 47 } 48 49 return new Loop(clear_opt(loop.insts)); 50 } 51 52 return inst; 53 }).array; 54 } 55 56 BrainfuckInstruction[] balanced_opt(BrainfuckInstruction[] insts) { 57 return insts.map!(delegate BrainfuckInstruction(inst) { 58 if(auto loop = cast(Loop) inst) { 59 auto loop_insts = loop.insts; 60 if(loop_insts.all!(loop_inst => (cast(Modify) loop_inst) || (cast(Select) loop_inst))) { 61 if(loop_insts 62 .filter!(loop_inst => cast(Select) loop_inst) 63 .map!(loop_inst => (cast(Select) loop_inst).amt) 64 .sum == 0) { 65 int[int] ms; 66 int pointer = 0; 67 68 foreach(loop_inst; loop_insts) { 69 if(auto modify = cast(Modify) loop_inst) { 70 ms[pointer] += modify.amt; 71 } else if(auto select = cast(Select) loop_inst) { 72 pointer += select.amt; 73 } 74 } 75 76 if(ms[0] == -1) { 77 ms.remove(0); 78 return new MoveLoop(ms); 79 } 80 } 81 } 82 83 return new Loop(balanced_opt(loop.insts)); 84 } 85 86 return inst; 87 }).array; 88 } 89 90 BrainfuckInstruction[] if_opt(BrainfuckInstruction[] insts) { 91 return insts.map!((inst) { 92 if(auto loop = cast(Loop) inst) { 93 int pointer; 94 ubyte[int] tape; 95 96 foreach(ref loop_inst; loop.insts) { 97 if(auto modify = cast(Modify) loop_inst) { 98 if(pointer in tape) 99 tape[pointer] += modify.amt; 100 } else if(auto select = cast(Select) loop_inst) { 101 pointer += select.amt; 102 } else if(cast(Clear) loop_inst) { 103 tape[pointer] = 0; 104 } else if(cast(Input) loop_inst) { 105 tape.remove(pointer); 106 } else if(cast(Loop) loop_inst || cast(MoveLoop) loop_inst) { 107 pointer = 0; 108 tape.clear; 109 tape[0] = 0; 110 111 if(auto inner_loop = cast(Loop) loop_inst) { 112 loop_inst = new Loop(if_opt(inner_loop.insts)); 113 } 114 } 115 } 116 117 if(pointer in tape && tape[pointer] == 0) { 118 return new If(loop.insts); 119 } 120 121 return inst; 122 } else { 123 return inst; 124 } 125 }).array; 126 } 127 128 BrainfuckInstruction[] unroll_opt(BrainfuckInstruction[] insts, bool program_body) { 129 int pointer; 130 ubyte[int] tape; 131 132 if(program_body) { 133 for(uint i = 0; i < 30000; i++) { 134 tape[i] = 0; 135 } 136 } 137 138 foreach(ref inst; insts) { 139 if(auto modify = cast(Modify) inst) { 140 if(pointer in tape) 141 tape[pointer] += modify.amt; 142 } else if(auto select = cast(Select) inst) { 143 pointer += select.amt; 144 } else if(cast(Clear) inst) { 145 tape[pointer] = 0; 146 } else if(cast(Input) inst) { 147 tape.remove(pointer); 148 } else if(cast(Loop) inst || cast(MoveLoop) inst) { 149 if(auto loop = cast(Loop) inst) { 150 if(pointer in tape) { 151 auto count = tape[pointer]; 152 int inner_pointer; 153 int[int] inner_tape; 154 155 foreach(inner_inst; loop.insts) { 156 if(auto modify = cast(Modify) inner_inst) { 157 inner_tape[inner_pointer] += modify.amt; 158 } else if(auto select = cast(Select) inner_inst) { 159 inner_pointer += select.amt; 160 } else if(cast(Clear) inner_inst) { 161 inner_tape[inner_pointer] = 0; 162 } else if(cast(Input) inner_inst) { 163 inner_tape.remove(inner_pointer); 164 } else if(cast(Loop) inner_inst || cast(MoveLoop) inner_inst) { 165 inner_pointer = 0; 166 inner_tape.clear; 167 inner_tape[0] = 0; 168 169 if(auto inner_loop = cast(Loop) inner_inst) { 170 inner_loop.insts = unroll_opt(inner_loop.insts, false); 171 } 172 } 173 } 174 175 if(0 in inner_tape && inner_tape[0] == -1 && inner_pointer == 0) { 176 inst = new UnrolledLoop(count, loop.insts); 177 } 178 } 179 } 180 181 pointer = 0; 182 tape.clear; 183 tape[0] = 0; 184 } 185 } 186 187 return insts; 188 }