Get all examples compiling, though output is not correct
[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   LIST,
16   STRING,
17   SYMBOL
18 };
19
20 enum Builtin;
21 typedef enum Builtin Builtin;
22 enum Builtin {
23   NIL,
24   POW,
25   PRINT
26 };
27
28 struct Object;
29 typedef struct Object Object;
30 struct Environment;
31 typedef struct Environment Environment;
32 struct Thread;
33 typedef struct Thread Thread;
34
35 struct Closure;
36 typedef struct Closure Closure;
37 struct Closure {
38   Environment* environment;
39   size_t entry;
40 };
41
42 struct List;
43 typedef struct List List;
44
45 union Value;
46 typedef union Value Value;
47 union Value {
48   Builtin builtin;
49   bool boolean;
50   Closure closure;
51   int32_t integer;
52   List* list;
53   char* string;
54   char* symbol;
55 };
56
57 struct Object {
58   Type type;
59   Value value;
60 };
61
62 struct List {
63   Object head;
64   List* tail;
65 };
66
67 #define BUILTIN_NIL (Object) { BUILTIN, (Value)(Builtin)NIL }
68
69 void Object_deinitialize(Object* self) {
70 }
71
72 {% include "environment.c" %}
73 {% include "stack.c" %}
74 {% include "frame.c" %}
75
76 struct Thread {
77   Frame frame;
78   Stack stack;
79 };
80
81 void Thread_initialize(Thread* self, size_t programCounter) {
82   Frame_initialize(&(self->frame), Environment_construct(NULL), NULL, programCounter);
83   Stack_initialize(&(self->stack));
84 }
85
86 void Thread_deinitialize(Thread* self) {
87   Frame_deinitialize(&(self->frame));
88   Stack_deinitialize(&(self->stack));
89 }
90
91 Environment* Thread_getEnvironment(Thread* self) {
92   return self->frame.environment;
93 }
94
95 void Thread_setProgramCounter(Thread* self, size_t programCounter) {
96   self->frame.programCounter = programCounter;
97 }
98
99 void Thread_incrementProgramCounter(Thread* self) {
100   self->frame.programCounter++;
101 }
102
103 size_t Thread_getProgramCounter(Thread* self) {
104   return self->frame.programCounter;
105 }
106
107 union Argument;
108 typedef const union Argument Argument;
109 union Argument {
110   size_t label;
111   void* pointer;
112   char* string;
113   int32_t integer;
114   char* symbol;
115 };
116
117 void callBuiltinPow(Thread* thread, size_t argumentCount) {
118   assert(argumentCount == 2);
119   assert(!Stack_isEmpty(&(thread->stack)));
120   Object exponent = Stack_pop(&(thread->stack));
121   assert(exponent.type == INTEGER);
122   assert(exponent.value.integer >= 0);
123
124   assert(!Stack_isEmpty(&(thread->stack)));
125   Object base = Stack_pop(&(thread->stack));
126   assert(base.type == INTEGER);
127
128   Object result;
129   result.type = INTEGER;
130   result.value.integer = 1;
131
132   while(exponent.value.integer > 0) {
133     result.value.integer *= base.value.integer;
134     exponent.value.integer--;
135   }
136
137   Stack_push(&(thread->stack), result);
138 }
139
140 void callBuiltinPrint(Thread* thread, size_t argumentCount) {
141   assert(argumentCount > 0);
142
143   Object arguments[argumentCount];
144   size_t count;
145
146   for(count = 0; count < argumentCount; count++) {
147     assert(!Stack_isEmpty(&(thread->stack)));
148     arguments[argumentCount - count - 1] = Stack_pop(&(thread->stack));
149   }
150
151   for(count = 0; count < argumentCount; count ++) {
152     Object arg = arguments[count];
153
154     switch(arg.type) {
155       case BOOLEAN:
156         if(arg.value.boolean) printf("true");
157         else printf("false");
158         break;
159
160       case INTEGER:
161         printf("%i", arg.value.integer);
162         break;
163
164       case STRING:
165         printf("%s", arg.value.string);
166         break;
167
168       default:
169         assert(false);
170     }
171   }
172
173   Stack_push(&(thread->stack), BUILTIN_NIL);
174 }
175
176 void callBuiltin(Thread* thread, Builtin b, size_t argumentCount) {
177   switch(b) {
178     case POW:
179       callBuiltinPow(thread, argumentCount);
180       break;
181     case PRINT:
182       callBuiltinPrint(thread, argumentCount);
183       break;
184
185     default:
186       assert(false);
187   }
188 }
189
190 void callClosure(Thread* thread, Closure closure, size_t argumentCount) {
191   assert(argumentCount == 0);
192
193   Frame* returnFrame = malloc(sizeof(Frame));
194   *returnFrame = thread->frame;
195   Frame_initialize(
196     &(thread->frame),
197     Environment_construct(Environment_reference(closure.environment)),
198     returnFrame,
199     closure.entry - 1 // We will increment the frame immediately after this
200   );
201 }
202
203 void inst_call(Thread* thread, Argument argument) {
204   assert(!Stack_isEmpty(&(thread->stack)));
205   Object f = Stack_pop(&(thread->stack));
206   size_t argumentCount = argument.label;
207
208   switch(f.type) {
209     case BUILTIN:
210       callBuiltin(thread, f.value.builtin, argumentCount);
211       break;
212
213     case CLOSURE:
214       callClosure(thread, f.value.closure, argumentCount);
215       break;
216
217     default:
218       assert(false);
219   }
220 }
221
222 void inst_concat(Thread* thread, Argument argument) {
223   assert(!Stack_isEmpty(&(thread->stack)));
224   Object left = Stack_pop(&(thread->stack));
225   assert(!Stack_isEmpty(&(thread->stack)));
226   Object right = Stack_pop(&(thread->stack));
227
228   assert(left.type == STRING);
229   assert(right.type == STRING);
230
231   char* resultString = malloc(strlen(left.value.string) + strlen(right.value.string) + 1);
232   resultString[0] = '\0';
233
234   strcat(resultString, left.value.string);
235   strcat(resultString, right.value.string);
236
237   Object resultObject = (Object) {
238     STRING,
239     (Value)resultString
240   };
241
242   Stack_push(&(thread->stack), resultObject);
243 }
244
245 {% with name='add', operation='+' %}
246   {% include "arithmetic_instruction.c" %}
247 {% endwith %}
248
249 void inst_close(Thread* thread, Argument argument) {
250   Object result;
251   result.type = CLOSURE;
252   result.value.closure.environment = Thread_getEnvironment(thread);
253   result.value.closure.entry = argument.label;
254
255   Stack_push(&(thread->stack), result);
256 }
257
258 void inst_drop(Thread* thread, Argument argument) {
259   assert(!Stack_isEmpty(&(thread->stack)));
260   Object result = Stack_pop(&(thread->stack));
261   Object_deinitialize(&result);
262 }
263
264 void inst_end(Thread* thread, Argument argument) {
265 }
266
267 {% with name='eq', operation='==' %}
268   {% include "comparison_instruction.c" %}
269 {% endwith %}
270
271 void inst_get(Thread* thread, Argument argument) {
272   assert(!Stack_isEmpty(&(thread->stack)));
273   Object listObject = Stack_pop(&(thread->stack));
274   assert(listObject.type == LIST);
275   List* list = listObject.value.list;
276
277   assert(!Stack_isEmpty(&(thread->stack)));
278   Object indexObject = Stack_pop(&(thread->stack));
279   assert(indexObject.type == INTEGER);
280   int32_t index = indexObject.value.integer;
281
282   while(index > 0) {
283     assert(list != NULL);
284     list = list->tail;
285     index--;
286   }
287
288   assert(list != NULL);
289   Stack_push(&(thread->stack), list->head);
290 }
291
292 {% with name='gt', operation='>' %}
293   {% include "comparison_instruction.c" %}
294 {% endwith %}
295
296 {% with name='gte', operation='>=' %}
297   {% include "comparison_instruction.c" %}
298 {% endwith %}
299
300 {% with name='idiv', operation='/' %}
301   {% include "arithmetic_instruction.c" %}
302 {% endwith %}
303
304 void inst_jump(Thread* thread, Argument argument) {
305   Thread_setProgramCounter(thread, argument.label - 1); // We will increment before running
306 }
307
308 void inst_jump_if_false(Thread* thread, Argument argument) {
309   assert(!Stack_isEmpty(&(thread->stack)));
310   Object result = Stack_pop(&(thread->stack));
311   assert(result.type == BOOLEAN);
312
313   if(!(result.value.boolean)) {
314     inst_jump(thread, argument);
315   }
316 }
317
318 void inst_list(Thread* thread, Argument argument) {
319   Object result;
320   result.type = LIST;
321   result.value.list = NULL;
322
323   while(argument.integer > 0) {
324     assert(!Stack_isEmpty(&(thread->stack)));
325     Object item = Stack_pop(&(thread->stack));
326
327     List* node = malloc(sizeof(List));
328     node->head = item;
329     node->tail = result.value.list;
330
331     result.value.list = node;
332   }
333
334   Stack_push(&(thread->stack), result);
335 }
336
337 {% with name='lt', operation='<' %}
338   {% include "comparison_instruction.c" %}
339 {% endwith %}
340
341 {% with name='lte', operation='<=' %}
342   {% include "comparison_instruction.c" %}
343 {% endwith %}
344
345 {% with name='mod', operation='%' %}
346   {% include "arithmetic_instruction.c" %}
347 {% endwith %}
348
349 {% with name='mul', operation='*' %}
350   {% include "arithmetic_instruction.c" %}
351 {% endwith %}
352
353 {% with name='neq', operation='!=' %}
354   {% include "comparison_instruction.c" %}
355 {% endwith %}
356
357 void inst_neg(Thread* thread, Argument argument) {
358   assert(!Stack_isEmpty(&(thread->stack)));
359   Object result = Stack_pop(&(thread->stack));
360   assert(result.type == INTEGER);
361
362   result.value.integer = -(result.value.integer);
363
364   Stack_push(&(thread->stack), result);
365 }
366
367 void inst_pop(Thread* thread, Argument argument) {
368   char* argumentString = argument.string;
369
370   assert(!Stack_isEmpty(&(thread->stack)));
371   Object result = Stack_pop(&(thread->stack));
372
373   if(strcmp(argumentString, "print") == 0) {
374     assert(false);
375   } else if(strcmp(argumentString, "pow") == 0) {
376     assert(false);
377   }
378
379
380   Environment_set(Thread_getEnvironment(thread), argumentString, result);
381 }
382
383 void inst_push(Thread* thread, Argument argument) {
384   char* argumentString = argument.string;
385
386   if(strcmp(argumentString, "false") == 0) {
387     Stack_push(&(thread->stack), (Object){ BOOLEAN, false });
388   }else if(strcmp(argumentString, "pow") == 0) {
389     Object result;
390     result.type = BUILTIN;
391     result.value.builtin = POW;
392     Stack_push(&(thread->stack), result);
393   } else if(strcmp(argumentString, "print") == 0) {
394     Object result;
395     result.type = BUILTIN;
396     result.value.builtin = PRINT;
397     Stack_push(&(thread->stack), result);
398   } else if(strcmp(argumentString, "true") == 0) {
399     Stack_push(&(thread->stack), (Object){ BOOLEAN, true });
400   } else {
401     Environment_get_Result result = Environment_get(
402       Thread_getEnvironment(thread),
403       argumentString
404     );
405     if(!result.found) {
406       fprintf(stderr, "Variable `%s` not found", argumentString);
407       assert(false);
408     }
409     Stack_push(&(thread->stack), result.result);
410   }
411 }
412
413 void inst_push_integer(Thread* thread, Argument argument) {
414   Object result;
415   result.type = INTEGER;
416   result.value.integer = argument.integer;
417
418   Stack_push(&(thread->stack), result);
419 }
420
421 void inst_push_string(Thread* thread, Argument argument) {
422   Object result;
423   result.type = STRING;
424   result.value.string = argument.string;
425
426   Stack_push(&(thread->stack), result);
427 }
428
429 void inst_push_symbol(Thread* thread, Argument argument) {
430   // TODO Store symbols in a symbol table so they can be looked up by reference
431   // without string comparison
432   Object result;
433   result.type = SYMBOL;
434   result.value.symbol = argument.symbol;
435 }
436
437 {% with name='sub', operation='-' %}
438   {% include "arithmetic_instruction.c" %}
439 {% endwith %}
440
441 void inst_return(Thread* thread, Argument argument) {
442   Frame* returnFrame = thread->frame.returnFrame;
443
444   Frame_deinitialize(&(thread->frame));
445
446   Frame_initialize(
447     &(thread->frame),
448     returnFrame->environment,
449     returnFrame->returnFrame,
450     returnFrame->programCounter
451   );
452
453   free(returnFrame);
454 }
455
456 void inst_structure(Thread* thread, Argument argument) {
457   assert(false);
458 }
459
460 struct Instruction;
461 typedef const struct Instruction Instruction;
462 struct Instruction {
463   void (*instruction)(Thread*,Argument);
464   Argument argument;
465 };
466
467 {% for label in labels_to_instruction_indices.keys() %}
468 #define LABEL_{{ label }} {{ labels_to_instruction_indices[label] }}
469 {% endfor %}
470
471 const Instruction program[] = {
472 {% for instruction in instruction_list %}
473   (Instruction){ inst_{{ instruction.instruction }}, (Argument){{ generate_argument(instruction) }} },
474 {% endfor %}
475 };
476
477 int main() {
478   Thread thread;
479   Thread_initialize(&thread, LABEL___main__);
480
481   for(; program[Thread_getProgramCounter(&thread)].instruction != inst_end; Thread_incrementProgramCounter(&thread)) {
482     program[Thread_getProgramCounter(&thread)].instruction(
483       &thread,
484       program[Thread_getProgramCounter(&thread)].argument
485     );
486   }
487
488   Thread_deinitialize(&thread);
489
490   return 0;
491 }