5ca9f61986c91bfa6583c721c21c146545ac6b10
[fur] / templates / program2.c
1 #include<assert.h>
2 #include<stdbool.h>
3 #include<stdint.h>
4 #include<stdio.h>
5 #include<stdlib.h>
6 #include<string.h>
7
8 enum Type;
9 typedef enum Type Type;
10 enum Type {
11   BOOLEAN,
12   BUILTIN,
13   CLOSURE,
14   INTEGER,
15   STRING
16 };
17
18 enum Builtin;
19 typedef enum Builtin Builtin;
20 enum Builtin {
21   NIL,
22   POW,
23   PRINT
24 };
25
26 struct Object;
27 typedef struct Object Object;
28 struct Environment;
29 typedef struct Environment Environment;
30 struct Thread;
31 typedef struct Thread Thread;
32
33 struct Closure;
34 typedef struct Closure Closure;
35 struct Closure {
36   Environment* environment;
37   size_t entry;
38 };
39
40 union Value;
41 typedef union Value Value;
42 union Value {
43   Builtin builtin;
44   Closure closure;
45   bool boolean;
46   char* string;
47   int32_t integer;
48 };
49
50 struct Object {
51   Type type;
52   Value value;
53 };
54
55 #define BUILTIN_NIL (Object) { BUILTIN, (Value)(Builtin)NIL }
56
57 void Object_deinitialize(Object* self) {
58 }
59
60 {% include "environment.c" %}
61 {% include "stack.c" %}
62 {% include "frame.c" %}
63
64 struct Thread {
65   Frame frame;
66   Stack stack;
67 };
68
69 void Thread_initialize(Thread* self, size_t programCounter) {
70   Frame_initialize(&(self->frame), Environment_construct(NULL), NULL, programCounter);
71   Stack_initialize(&(self->stack));
72 }
73
74 void Thread_deinitialize(Thread* self) {
75   Frame_deinitialize(&(self->frame));
76   Stack_deinitialize(&(self->stack));
77 }
78
79 Environment* Thread_getEnvironment(Thread* self) {
80   return self->frame.environment;
81 }
82
83 void Thread_setProgramCounter(Thread* self, size_t programCounter) {
84   self->frame.programCounter = programCounter;
85 }
86
87 void Thread_incrementProgramCounter(Thread* self) {
88   self->frame.programCounter++;
89 }
90
91 size_t Thread_getProgramCounter(Thread* self) {
92   return self->frame.programCounter;
93 }
94
95 union Argument;
96 typedef const union Argument Argument;
97 union Argument {
98   size_t label;
99   void* pointer;
100   char* string;
101   int32_t integer;
102 };
103
104 void callBuiltinPow(Thread* thread, size_t argumentCount) {
105   assert(argumentCount == 2);
106   assert(!Stack_isEmpty(&(thread->stack)));
107   Object exponent = Stack_pop(&(thread->stack));
108   assert(exponent.type == INTEGER);
109   assert(exponent.value.integer >= 0);
110
111   assert(!Stack_isEmpty(&(thread->stack)));
112   Object base = Stack_pop(&(thread->stack));
113   assert(base.type == INTEGER);
114
115   Object result;
116   result.type = INTEGER;
117   result.value.integer = 1;
118
119   while(exponent.value.integer > 0) {
120     result.value.integer *= base.value.integer;
121     exponent.value.integer--;
122   }
123
124   Stack_push(&(thread->stack), result);
125 }
126
127 void callBuiltinPrint(Thread* thread, size_t argumentCount) {
128   assert(argumentCount > 0);
129
130   Object arguments[argumentCount];
131   size_t count;
132
133   for(count = 0; count < argumentCount; count++) {
134     assert(!Stack_isEmpty(&(thread->stack)));
135     arguments[argumentCount - count - 1] = Stack_pop(&(thread->stack));
136   }
137
138   for(count = 0; count < argumentCount; count ++) {
139     Object arg = arguments[count];
140
141     switch(arg.type) {
142       case BOOLEAN:
143         if(arg.value.boolean) printf("true");
144         else printf("false");
145         break;
146
147       case INTEGER:
148         printf("%i", arg.value.integer);
149         break;
150
151       case STRING:
152         printf("%s", arg.value.string);
153         break;
154
155       default:
156         assert(false);
157     }
158   }
159
160   Stack_push(&(thread->stack), BUILTIN_NIL);
161 }
162
163 void callBuiltin(Thread* thread, Builtin b, size_t argumentCount) {
164   switch(b) {
165     case POW:
166       callBuiltinPow(thread, argumentCount);
167       break;
168     case PRINT:
169       callBuiltinPrint(thread, argumentCount);
170       break;
171
172     default:
173       assert(false);
174   }
175 }
176
177 void callClosure(Thread* thread, Closure closure, size_t argumentCount) {
178   assert(argumentCount == 0);
179
180   Frame* returnFrame = malloc(sizeof(Frame));
181   *returnFrame = thread->frame;
182   Frame_initialize(
183     &(thread->frame),
184     Environment_construct(Environment_reference(closure.environment)),
185     returnFrame,
186     closure.entry - 1 // We will increment the frame immediately after this
187   );
188 }
189
190 void inst_call(Thread* thread, Argument argument) {
191   assert(!Stack_isEmpty(&(thread->stack)));
192   Object f = Stack_pop(&(thread->stack));
193   size_t argumentCount = argument.label;
194
195   switch(f.type) {
196     case BUILTIN:
197       callBuiltin(thread, f.value.builtin, argumentCount);
198       break;
199
200     case CLOSURE:
201       callClosure(thread, f.value.closure, argumentCount);
202       break;
203
204     default:
205       assert(false);
206   }
207 }
208
209 {% with name='add', operation='+' %}
210   {% include "arithmetic_instruction.c" %}
211 {% endwith %}
212
213 void inst_close(Thread* thread, Argument argument) {
214   Object result;
215   result.type = CLOSURE;
216   result.value.closure.environment = Thread_getEnvironment(thread);
217   result.value.closure.entry = argument.label;
218
219   Stack_push(&(thread->stack), result);
220 }
221
222 void inst_drop(Thread* thread, Argument argument) {
223   assert(!Stack_isEmpty(&(thread->stack)));
224   Object result = Stack_pop(&(thread->stack));
225   Object_deinitialize(&result);
226 }
227
228 void inst_end(Thread* thread, Argument argument) {
229 }
230
231 {% with name='eq', operation='==' %}
232   {% include "comparison_instruction.c" %}
233 {% endwith %}
234
235 {% with name='gt', operation='>' %}
236   {% include "comparison_instruction.c" %}
237 {% endwith %}
238
239 {% with name='gte', operation='>=' %}
240   {% include "comparison_instruction.c" %}
241 {% endwith %}
242
243 {% with name='idiv', operation='/' %}
244   {% include "arithmetic_instruction.c" %}
245 {% endwith %}
246
247 void inst_jump(Thread* thread, Argument argument) {
248   Thread_setProgramCounter(thread, argument.label - 1); // We will increment before running
249 }
250
251 void inst_jump_if_false(Thread* thread, Argument argument) {
252   assert(!Stack_isEmpty(&(thread->stack)));
253   Object result = Stack_pop(&(thread->stack));
254   assert(result.type == BOOLEAN);
255
256   if(!(result.value.boolean)) {
257     inst_jump(thread, argument);
258   }
259 }
260
261 {% with name='lt', operation='<' %}
262   {% include "comparison_instruction.c" %}
263 {% endwith %}
264
265 {% with name='lte', operation='<=' %}
266   {% include "comparison_instruction.c" %}
267 {% endwith %}
268
269 {% with name='mod', operation='%' %}
270   {% include "arithmetic_instruction.c" %}
271 {% endwith %}
272
273 {% with name='mul', operation='*' %}
274   {% include "arithmetic_instruction.c" %}
275 {% endwith %}
276
277 {% with name='neq', operation='!=' %}
278   {% include "comparison_instruction.c" %}
279 {% endwith %}
280
281 void inst_neg(Thread* thread, Argument argument) {
282   assert(!Stack_isEmpty(&(thread->stack)));
283   Object result = Stack_pop(&(thread->stack));
284   assert(result.type == INTEGER);
285
286   result.value.integer = -(result.value.integer);
287
288   Stack_push(&(thread->stack), result);
289 }
290
291 void inst_pop(Thread* thread, Argument argument) {
292   char* argumentString = argument.string;
293
294   assert(!Stack_isEmpty(&(thread->stack)));
295   Object result = Stack_pop(&(thread->stack));
296
297   if(strcmp(argumentString, "print") == 0) {
298     assert(false);
299   } else if(strcmp(argumentString, "pow") == 0) {
300     assert(false);
301   }
302
303
304   Environment_set(Thread_getEnvironment(thread), argumentString, result);
305 }
306
307 void inst_push(Thread* thread, Argument argument) {
308   char* argumentString = argument.string;
309
310   if(strcmp(argumentString, "false") == 0) {
311     Stack_push(&(thread->stack), (Object){ BOOLEAN, false });
312   }else if(strcmp(argumentString, "pow") == 0) {
313     Object result;
314     result.type = BUILTIN;
315     result.value.builtin = POW;
316     Stack_push(&(thread->stack), result);
317   } else if(strcmp(argumentString, "print") == 0) {
318     Object result;
319     result.type = BUILTIN;
320     result.value.builtin = PRINT;
321     Stack_push(&(thread->stack), result);
322   } else if(strcmp(argumentString, "true") == 0) {
323     Stack_push(&(thread->stack), (Object){ BOOLEAN, true });
324   } else {
325     Environment_get_Result result = Environment_get(
326       Thread_getEnvironment(thread),
327       argumentString
328     );
329     if(!result.found) {
330       fprintf(stderr, "Variable `%s` not found", argumentString);
331       assert(false);
332     }
333     Stack_push(&(thread->stack), result.result);
334   }
335 }
336
337 void inst_push_integer(Thread* thread, Argument argument) {
338   Object result;
339   result.type = INTEGER;
340   result.value.integer = argument.integer;
341
342   Stack_push(&(thread->stack), result);
343 }
344
345 void inst_push_string(Thread* thread, Argument argument) {
346   Object result;
347   result.type = STRING;
348   result.value.string = argument.string;
349
350   Stack_push(&(thread->stack), result);
351 }
352
353 {% with name='sub', operation='-' %}
354   {% include "arithmetic_instruction.c" %}
355 {% endwith %}
356
357 void inst_return(Thread* thread, Argument argument) {
358   Frame* returnFrame = thread->frame.returnFrame;
359
360   Frame_deinitialize(&(thread->frame));
361
362   Frame_initialize(
363     &(thread->frame),
364     returnFrame->environment,
365     returnFrame->returnFrame,
366     returnFrame->programCounter
367   );
368
369   free(returnFrame);
370 }
371
372 struct Instruction;
373 typedef const struct Instruction Instruction;
374 struct Instruction {
375   void (*instruction)(Thread*,Argument);
376   Argument argument;
377 };
378
379 {% for label in labels_to_instruction_indices.keys() %}
380 #define LABEL_{{ label }} {{ labels_to_instruction_indices[label] }}
381 {% endfor %}
382
383 const Instruction program[] = {
384 {% for instruction in instruction_list %}
385   (Instruction){ inst_{{ instruction.instruction }}, (Argument){{ generate_argument(instruction) }} },
386 {% endfor %}
387 };
388
389 int main() {
390   Thread thread;
391   Thread_initialize(&thread, LABEL___main__);
392
393   for(; program[Thread_getProgramCounter(&thread)].instruction != inst_end; Thread_incrementProgramCounter(&thread)) {
394     program[Thread_getProgramCounter(&thread)].instruction(
395       &thread,
396       program[Thread_getProgramCounter(&thread)].argument
397     );
398   }
399
400   Thread_deinitialize(&thread);
401
402   return 0;
403 }