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