1 module brainfuck;
2 
3 import std.conv;
4 import std.array;
5 import std.stdio;
6 import std.format;
7 
8 class VM {
9     uint pointer = 0;
10     ubyte[] tape;
11 
12     this() {
13         tape.length = 30000;
14     }
15 }
16 
17 class BrainfuckInstruction {
18     abstract void run(VM);
19     abstract string compile(uint);
20     abstract string to_string(uint);
21 
22     string compile() {
23         return compile(0);
24     }
25 
26     string to_string() {
27         return to_string(0);
28     }
29 }
30 
31 class Modify : BrainfuckInstruction {
32     int amt;
33 
34     this(int amt) {
35         this.amt = amt;
36     }
37 
38     override void run(VM vm) {
39         vm.tape[vm.pointer] += amt;
40     }
41 
42     override string compile(uint depth) {
43         return "    ".replicate(depth) ~ "*p += %s;".format(amt);
44     }
45 
46     override string to_string(uint depth) {
47         return "    ".replicate(depth) ~ "Modify(" ~ amt.to!string ~ ")";
48     }
49 }
50 
51 class Select : BrainfuckInstruction {
52     int amt;
53 
54     this(int amt) {
55         this.amt = amt;
56     }
57 
58     override void run(VM vm) {
59         vm.pointer += amt;
60     }
61 
62     override string compile(uint depth) {
63         return "    ".replicate(depth) ~ "p += %s;".format(amt);
64     }
65 
66     override string to_string(uint depth) {
67         return "    ".replicate(depth) ~ "Select(" ~ amt.to!string ~ ")";
68     }
69 }
70 
71 class Loop : BrainfuckInstruction {
72     BrainfuckInstruction[] insts;
73 
74     this(BrainfuckInstruction[] insts) {
75         this.insts = insts;
76     }
77 
78     override void run(VM vm) {
79         while(vm.tape[vm.pointer] != 0) {
80             foreach(inst; insts) {
81                 inst.run(vm);
82             }
83         }
84     }
85 
86     override string compile(uint depth) {
87         char[] s;
88         s ~= "    ".replicate(depth) ~ "while(*p) {\n";
89 
90         foreach(inst; insts) {
91             s ~= inst.compile(depth + 1) ~ "\n";
92         }
93 
94         s ~= "    ".replicate(depth) ~ "}";
95         return cast(string) s;
96     }
97 
98     override string to_string(uint depth) {
99         char[] s;
100         s ~= "    ".replicate(depth) ~ "Loop {\n";
101 
102         foreach(inst; insts) {
103             s ~= inst.to_string(depth + 1) ~ "\n";
104         }
105 
106         s ~= "    ".replicate(depth) ~ "}";
107         return cast(string) s;
108     }
109 }
110 
111 class Input : BrainfuckInstruction {
112     override void run(VM vm) {
113         char c;
114         readf("%s", &c);
115         vm.tape[vm.pointer] = c;
116     }
117 
118     override string compile(uint depth) {
119         return "    ".replicate(depth) ~ "*p = getchar();";
120     }
121 
122     override string to_string(uint depth) {
123         return "    ".replicate(depth) ~ "Input";
124     }
125 }
126 
127 class Output : BrainfuckInstruction {
128     override void run(VM vm) {
129         write(cast(char) vm.tape[vm.pointer]);
130         stdout.flush();
131     }
132 
133     override string compile(uint depth) {
134         return "    ".replicate(depth) ~ "putchar(*p); fflush(stdout);";
135     }
136 
137     override string to_string(uint depth) {
138         return "    ".replicate(depth) ~ "Output";
139     }
140 }
141 
142 class Clear : BrainfuckInstruction {
143     override void run(VM vm) {
144         vm.tape[vm.pointer] = 0;
145     }
146 
147     override string compile(uint depth) {
148         return "    ".replicate(depth) ~ "*p = 0;";
149     }
150 
151     override string to_string(uint depth) {
152         return "    ".replicate(depth) ~ "Clear";
153     }
154 }
155 
156 class MoveLoop : BrainfuckInstruction {
157     int[int] modifications;
158 
159     this(int[int] modifications) {
160         this.modifications = modifications;
161     }
162 
163     override void run(VM vm) {
164         auto src = vm.tape[vm.pointer];
165         if(src == 0) return;
166 
167         foreach(pointer, modify; modifications) {
168             vm.tape[vm.pointer + pointer] += modify * src;
169         }
170 
171         vm.tape[vm.pointer] = 0;
172     }
173 
174     override string compile(uint depth) {
175         char[] s;
176         s ~= "    ".replicate(depth) ~ "if(*p) {\n";
177 
178         foreach(pointer, modify; modifications) {
179             s ~= "    ".replicate(depth + 1) ~ "*(p + %s) += %s * (*p);\n".format(pointer, modify);
180         }
181 
182         s ~= "    ".replicate(depth + 1) ~ "*p = 0;\n";
183         s ~= "    ".replicate(depth) ~ "}";
184         return cast(string) s;
185     }
186 
187     override string to_string(uint depth) {
188         return "    ".replicate(depth) ~ "MoveLoop " ~ modifications.to!string;
189     }
190 }